Promise
为什么要使用 Promise
- 指定回调函数的方式更加灵活:
- 回调函数:必须在启动异步任务前指定
promise:启动异步任务 → 返回promise对象 → 给promise对象绑定回调函数(甚至可以在异步任务结束后指定多个;一个promise指定多个成功/失败回调函数, 状态变化时都会调用)
- 支持链式调用,
Promise可以用来解决回调地狱(外部回调函数异步执行的结果是嵌套的回调执行的条件)的问题
Promise 执行流程

Promise 的基本用法
- 实例化
Promise构造函数生成实例对象
const p = new Promise((resolve, reject) => {})
resolve函数:内部定义成功时调用的函数reject函数:内部定义失败时调用的函数
Promise对象状态属性
(1)一开始声明后不进行任何操作,就是 pending,未完成
(2)执行 resolve函数,变成fulfilled,已成功
(3)执行reject函数(或抛出异常),变成 rejected,已失败
(4)Promise 函数的两个参数可以任意命名,但是功能并不会改变
(5)Promise 的状态一旦发生变化,就不会再改变,即Promise 函数里的resolve或是 reject 只执行第一个
const p = new Promise((resolve, reject) => {
// pending->fulfilled
// resolve(value); //可以传递参数,在then()方法的第一个回调函数中接收
// pending->rejected
// throw '异常信息'
//reject(reson); //可以传递参数,在then()方法的第二个回调函数中接收
})
实例方法
Promise.prototype.then()
(1)resolve():状态 pending->fulfilled 的时候,执行 then 方法的第一个回调函数
(2)reject():状态 pending->rejected 的时候,执行 then 方法的第二个回调函数
const p = new Promise((resolve, reject) => {
// resolve 和 reject 函数的参数
// resolve('success'); //传的是字符串
// resolve({ username: 'frank' }); //传的是对象
reject(new Error('reason')) //传的是错误对象
})
p.then(
(data) => {
//data接收的是成功状态下,resolve函数传递的参数
console.log('success', data)
},
(err) => {
//err接收的是失败状态下,reject函数传递的参数
console.log('error', err)
}
)
then 正常返回fulfilled的Promise,如果出现异常则返回 rejected状态的Promise
const p = new Promise((resolve, reject) => {
resolve('frank')
})
p.then((value) => {
console.log(value) // frank
// 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
return 456
}).then((value) => {
console.log(value) // 456
})
const p = new Promise((resolve, reject) => {
resolve('frank')
})
p.then((value) => {
console.log(value)
// 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
throw '错啦!'
}).then(
(a) => {
console.log(a)
},
// 执行失败的回调
(err) => {
console.log(err)
}
)
const p = new Promise((resolve, reject) => {
resolve('frank')
})
p.then((value) => {
console.log(value)
// 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果
return new Promise((resolve, reject) => {
resolve('123')
})
}).then((value) => {
console.log(value) // 123
})
Promise.prototype.catch()
catch本质是then的特例,它只能指定失败的回调,不能指定成功的回调catch正常返回fulfilled的Promise,里面有报错则返回rejected
const p = new Promise((resolve, reject) => {
reject('err')
})
.catch((err) => {
console.log(err)
return 123
})
.then((data) => {
console.log(data) // 123
})
Promise.prototype.finally()
finally()方法返回一个 Promise。在 promise 结束时,无论结果是 fulfilled 或者是rejected,都会执行指定的回调函数。这为在 Promise 是否成功完成后都需要执行的代码提供了一种方式
p.finally(function () {
// 返回状态为(resolved 或 rejected)
})
构造函数方法
Promise.resolve()
Promise.resolve(), 返回一个成功/失败的 Promise 对象的一种简写形式
new Promise((resolve) => resolve('foo'))
// 简写
Promise.resolve('foo')
- 参数
- 一般参数(非
Promise对象),返回的结果为成功Promise对象
Promise.resolve('foo').then((data) => {
console.log(data)
})
- 以
Promise对象当做参数
如果传入的参数是 Promise 对象,则参数的结果决定了Promise.resolve()的结果
const p = Promise.resolve(
new Promise((resolve, reject) => {
reject(123)
})
)
console.log(p) // Promise {<rejected>: 123}
p.catch((err) => {
console.log(err)
})
Promise.reject()
Promise.reject(),返回一个失败状态 Promise 对象的一种简写形式
new Promise((resolve, reject) => {
reject('reason')
})
// 等价于
Promise.reject('reason')
与 Promise.resolve()不同,Promise.reject()不管什么参数,它返回的结果永远都是失败的,而且传入什么参数,失败的结果就是什么(传入 promise,失败的结果也是 promise)
Promise.all()
传入的 Promise 实例对象所有状态都变成 resolved,最终的状态才会变成 resolved,只要有一个变成 rejected,最终的状态就变成 rejected
基本用法
const delay = (ms) => {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
const p1 = delay(1000).then(() => {
console.log('p1 完成了')
return 'p1'
// return Promise.reject('reason1');
})
const p2 = delay(2000).then(() => {
console.log('p2 完成了')
return 'p2'
// return Promise.reject('reason2');
})
const p = Promise.all([p1, p2])
p.then(
(data) => {
console.log(data) //["p1", "p2"]
},
(err) => {
console.log(err) // 如果都失败,失败结果为第一个失败的Promise的结果
}
)
Promise.race()
最终状态取决于第一个完成的Promise实例对象,如果第一个完成的成功了,那最终的就成功;如果第一个完成的失败了,那最终的就失败
const delay = (ms) => {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
const p1 = delay(1000).then(() => {
console.log('p1 完成了')
return 'p1'
// return Promise.reject('reason1');
})
const p2 = delay(2000).then(() => {
console.log('p2 完成了')
return 'p2'
// return Promise.reject('reason2');
})
const r = Promise.race([p1, p2])
r.then(
(data) => {
console.log(data) // p1
},
(err) => {
console.log(err)
}
)
Promise.allSettled()
Promise.allSettled() 只会真实记录下各个 Promise 的表现,最终状态永远都是成功的
const delay = (ms) => {
return new Promise((resolve) => {
setTimeout(resolve, ms)
})
}
const p1 = delay(1000).then(() => {
console.log('p1 完成了')
return 'p1'
// return Promise.reject('reason');
})
const p2 = delay(2000).then(() => {
console.log('p2 完成了')
// return 'p2';
return Promise.reject('reason')
})
const allSettledPromise = Promise.allSettled([p1, p2])
allSettledPromise.then((data) => {
console.log(data)
// [
// { status: 'fulfilled', value: 'p1' },
// { status: 'rejected', reason: 'reason' }
// ]
})
Promise.any()
当所有 Promise 实例都变成 rejected 状态,返回的 Promise 才会变成 rejected 状态,参数中只要有一个 Promise 改变为成功状态,则返回的 Promise 状态就是成功的状态:
- 参数中只有一个成功状态的
Promise实例
// 失败
const p1 = new Promise((resolve, reject) => {
reject()
})
// 失败
const p2 = new Promise((resolve, reject) => {
reject()
})
// 成功
const p3 = new Promise((resolve) => {
resolve('p3成功!')
})
const res = Promise.any([p1, p3, p2])
res.then((value) => {
console.log(value)
})
- 参数中全部是失败状态的
Promise实例
// 失败
const p1 = new Promise((resolve, reject) => {
reject()
})
// 失败
const p2 = new Promise((resolve, reject) => {
reject()
})
// 失败
const p3 = new Promise((resolve, reject) => {
reject()
})
const res = Promise.any([p1, p3, p2])
res
.then((value) => {
console.log(value)
})
.catch((err) => {
console.log(err) // AggregateError: All promises were rejected
console.log(typeof err) // object
console.log(err.errors) // ['p1失败', 'p3失败', 'p2失败']
})
- 实际开发中,可能会有这样的需求:一次性加载多张图片,哪一张先加载出来就显示哪一张。那么此时就可以使用
Promise.any()方法实现效果
const root = document.querySelector('.root')
// 加载错误
const url1 =
'https://v.api.aa1.cn/api/api-tx/img/1798ssss.jpg%E5%AE%98%E7%BD%91api.aa1.cn%E5%85%8D%E8%B4%B9%E8%A7%86%E9%A2%91API.jpg'
// 可以加载
const url2 =
'https://v.api.aa1.cn/api/api-tx/img/1093.jpg%E5%AE%98%E7%BD%91api.aa1.cn%E5%85%8D%E8%B4%B9%E8%A7%86%E9%A2%91API.jpg'
function loadImg(url) {
const img = new Image(200, 200)
return new Promise(function (resolve, reject) {
img.src = url
img.onload = () => {
resolve(img)
}
img.error = () => {
throw '图片加载异常,请检查网络'
}
})
}
const promiseArr = [loadImg(url1), loadImg(url2)]
Promise.any(promiseArr)
.then((res) => {
root.appendChild(res)
})
.catch((err) => {
console.log(err)
})
<div class="root"></div>

