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>