1. Promise.prototype.finally
finally()方法用于指定不管 Promise 对象最后状态如何,都会执行的操作
finally 本质上是 then 方法的特例。
- finally 无论外面的 promise 状态成功还是失败 都要走 并且回调函数不带参数
- 正常走 finallu 之后 then 或者 catch
- 如果 finally 内部有 promise 并且有延时处理,整个 finall 会等待执行
- 如果 2 个都是成功,取外面结果
- 如果外面是成功 里面是失败,取里面失败的结果
- 如果外面是失败 里面是成功 取外面失败的结果
- 如果外面和里面都是失败,取里面失败的结果
- 如果外面成功,里面成功,取外面成功的结果
promise.finally(() => {
// 语句
})
// 等同于
promise.then(
(result) => {
// 语句
return result
},
(error) => {
// 语句
throw error
},
)
promise.finally(() => {
// 语句
})
// 等同于
promise.then(
(result) => {
// 语句
return result
},
(error) => {
// 语句
throw error
},
)
Promise.prototype.finally = function (callback) {
let P = this.constructor
return this.then(
(value) => P.resolve(callback()).then(() => value),
(reason) =>
P.resolve(callback()).then(() => {
throw reason
}),
)
}
Promise.prototype.finally = function (callback) {
let P = this.constructor
return this.then(
(value) => P.resolve(callback()).then(() => value),
(reason) =>
P.resolve(callback()).then(() => {
throw reason
}),
)
}
Promise.reject('value1')
.finally(() => {
return new Promise((resolve, reject) => {
resolve('成功')
reject('失败')
})
})
.then(
(value) => {
console.log(value)
},
(err) => {
console.log(err)
},
)
Promise.reject('value1')
.finally(() => {
return new Promise((resolve, reject) => {
resolve('成功')
reject('失败')
})
})
.then(
(value) => {
console.log(value)
},
(err) => {
console.log(err)
},
)
2.Promise.all
const p = Promise.all([p1, p2, p3])
const p = Promise.all([p1, p2, p3])
Promise.all()方法接受一个数组作为参数,如果不是,就会先调用下面讲到的 Promise.resolve 方法,将参数转为 Promise 实例,Promise.all()方法的参数可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例
(1)只有 p1、p2、p3 的状态都变成 fulfilled,p 的状态才会变成 fulfilled,此时 p1、p2、p3 的返回值组成一个数组,传递给 p 的回调函数。
(2)只要 p1、p2、p3 之中有一个被 rejected,p 的状态就变成 rejected,此时第一个被 reject 的实例的返回值,会传递给 p 的回调函数
口诀:全真则真,一假则假
3.Promise.race
Promise.race()方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例。
const p = Promise.race([p1, p2, p3])
const p = Promise.race([p1, p2, p3])
上面代码中,只要 p1、p2、p3 之中有一个实例率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数。
口诀:谁先确定选谁
4. Promise.allSettled
Promise.allSettled()方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象。只有等到参数数组的所有 Promise 对象都发生状态变更(不管是 fulfilled 还是 rejected),返回的 Promise 对象才会发生状态变更。
该方法返回的新的 Promise 实例,一旦发生状态变更,状态总是 fulfilled,不会变成 rejected。状态变成 fulfilled 后,它的回调函数会接收到一个数组作为参数,该数组的每个成员对应前面数组的每个 Promise 对象。
const p1 = new Promise((resolve) => {
setTimeout(() => {
resolve(11)
}, 3000)
})
const p2 = new Promise((resolve) => {
setTimeout(() => {
resolve(22)
}, 3000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(33)
}, 1000)
})
Promise.allSettled([p1, p2, p3])
.then(
(value) => {
console.log(value)
let arr = []
for (let item of value) {
arr.push(item.value)
}
return arr
},
(err) => {
console.log(err)
},
)
.then((value) => {
console.log(value)
})
.catch((err) => {
console.log(err)
})
const p1 = new Promise((resolve) => {
setTimeout(() => {
resolve(11)
}, 3000)
})
const p2 = new Promise((resolve) => {
setTimeout(() => {
resolve(22)
}, 3000)
})
const p3 = new Promise((resolve, reject) => {
setTimeout(() => {
reject(33)
}, 1000)
})
Promise.allSettled([p1, p2, p3])
.then(
(value) => {
console.log(value)
let arr = []
for (let item of value) {
arr.push(item.value)
}
return arr
},
(err) => {
console.log(err)
},
)
.then((value) => {
console.log(value)
})
.catch((err) => {
console.log(err)
})
口诀: 等待所有状态
5.源码
点击这里展开/折叠代码块
const PENDING = 'PENDING',
FULFILLED = 'FULFILLED',
REJECTED = 'REJECTED'
const resolvePromise = function (promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(
new TypeError('Chaining cycle detected for promise #<MyPromise>'),
)
}
let called = false
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
let then = x.then
// 这里使用try的原因是访问x的then方法它有可能被劫持然后抛错
// Object.defineProperty(x,'then',{throw new Error("this is a error")})
try {
if (typeof then === 'function') {
then.call(
x,
(y) => {
if (called) return
called = true
resolvePromise(promise2, y, resolve, reject)
},
(r) => {
if (called) return
called = true
reject(r)
},
)
} else {
resolve(x)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
resolve(x)
}
}
class MyPromise {
constructor(excutor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onResolveCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (value instanceof MyPromise) {
value.then(resolve, reject)
return
}
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
this.onResolveCallbacks.forEach((fn) => fn())
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach((fn) => fn())
}
}
try {
excutor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === 'function' ? onFulfilled : (value) => value
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason
}
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === PENDING) {
this.onResolveCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
})
return promise2
}
catch(callbackErros) {
return this.then(null, callbackErros)
}
finally(finallyCallback) {
return this.then(
// value 和 reason 是上一个promise的值,我们需要缓存下来
(value) => {
return MyPromise.resolve(finallyCallback()).then(() => value)
},
(reason) => {
console.log(reason)
return MyPromise.resolve(finallyCallback()).then(() => {
throw reason
})
},
)
}
static resolve(value) {
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
static all(promiseArr) {
if (!isIterable(promiseArr)) {
let type = typeof promiseArr
throw TypeError(`${type} is not a iterable (cannot read property Symbol(Symbol.iterator))
at Function.all (<anonymous>)`)
}
let resArr = [],
idx = 0
return new Promise((resolve, reject) => {
promiseArr.map((promise, index) => {
if (isPromise(promise)) {
promise.then((res) => {
formatArr(res, index, resolve)
}, reject)
} else {
formatArr(promise, index, resolve)
}
})
})
function formatArr(value, index, resolve) {
resArr[index] = value
// if(resArr.length ===promiseArr.length) 在某些时刻不正确,比如数组最后一项先执行完 数组就为[empty,empty,value]
if (++idx === promiseArr.length) {
resolve(resArr)
}
}
}
static allSettled(promiseArr) {
let resArr = [],
idx = 0
if (!isIterable(promiseArr)) {
throw new TypeError(`${promiseArr} is not a iterable`)
}
return new Promise((resolve, reject) => {
if (promiseArr.length === 0) {
resolve([])
}
promiseArr.forEach((promise, index) => {
if (isPromise(promise)) {
promise.then(
(value) => {
formatResArr('fulfilled', promise, index, resolve)
},
(reason) => {
formatResArr('rejected', reason, index, resolve)
},
)
} else {
//普通值
formatResArr('fulfilled', promise, index, resolve)
}
})
})
function formatResArr(status, value, index, resolve) {
switch (status) {
case 'fulfilled':
resArr[index] = {
status,
value,
}
break
case 'rejected':
resArr[index] = {
status,
reason: value,
}
break
default:
break
}
if (++idx === promiseArr.length) {
resolve(resArr)
}
}
}
static race(promiseArr) {
if (!isIterable(promiseArr)) {
let type = typeof promiseArr
throw TypeError(`${type} is not a iterable (cannot read property Symbol(Symbol.iterator))
at Function.all (<anonymous>)`)
}
return new Promise((resolve, reject) => {
promiseArr.forEach((promise) => {
if (isPromise(promise)) {
promise.then(resolve, reject)
} else {
resolve(promise)
}
})
})
}
}
function isPromise(x) {
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
let then = x.then
return typeof then === 'function'
}
return false
}
function isIterable(value) {
return (
value !== null &&
value !== undefined &&
typeof value[Symbol.iterator] === 'function'
)
}
// MyPromise.defer = MyPromise.deferred = function () {
// let dfd = {}
// dfd.promise = new MyPromise((resolve, reject) => {
// dfd.resolve = resolve
// dfd.reject = reject
// })
// return dfd
// }
// module.exports = MyPromise
const PENDING = 'PENDING',
FULFILLED = 'FULFILLED',
REJECTED = 'REJECTED'
const resolvePromise = function (promise2, x, resolve, reject) {
if (promise2 === x) {
return reject(
new TypeError('Chaining cycle detected for promise #<MyPromise>'),
)
}
let called = false
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
let then = x.then
// 这里使用try的原因是访问x的then方法它有可能被劫持然后抛错
// Object.defineProperty(x,'then',{throw new Error("this is a error")})
try {
if (typeof then === 'function') {
then.call(
x,
(y) => {
if (called) return
called = true
resolvePromise(promise2, y, resolve, reject)
},
(r) => {
if (called) return
called = true
reject(r)
},
)
} else {
resolve(x)
}
} catch (e) {
if (called) return
called = true
reject(e)
}
} else {
resolve(x)
}
}
class MyPromise {
constructor(excutor) {
this.status = PENDING
this.value = undefined
this.reason = undefined
this.onResolveCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
if (value instanceof MyPromise) {
value.then(resolve, reject)
return
}
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
this.onResolveCallbacks.forEach((fn) => fn())
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
this.onRejectedCallbacks.forEach((fn) => fn())
}
}
try {
excutor(resolve, reject)
} catch (e) {
reject(e)
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === 'function' ? onFulfilled : (value) => value
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason
}
let promise2 = new MyPromise((resolve, reject) => {
if (this.status === FULFILLED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
}
if (this.status === PENDING) {
this.onResolveCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason)
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
})
})
}
})
return promise2
}
catch(callbackErros) {
return this.then(null, callbackErros)
}
finally(finallyCallback) {
return this.then(
// value 和 reason 是上一个promise的值,我们需要缓存下来
(value) => {
return MyPromise.resolve(finallyCallback()).then(() => value)
},
(reason) => {
console.log(reason)
return MyPromise.resolve(finallyCallback()).then(() => {
throw reason
})
},
)
}
static resolve(value) {
return new MyPromise((resolve, reject) => {
resolve(value)
})
}
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason)
})
}
static all(promiseArr) {
if (!isIterable(promiseArr)) {
let type = typeof promiseArr
throw TypeError(`${type} is not a iterable (cannot read property Symbol(Symbol.iterator))
at Function.all (<anonymous>)`)
}
let resArr = [],
idx = 0
return new Promise((resolve, reject) => {
promiseArr.map((promise, index) => {
if (isPromise(promise)) {
promise.then((res) => {
formatArr(res, index, resolve)
}, reject)
} else {
formatArr(promise, index, resolve)
}
})
})
function formatArr(value, index, resolve) {
resArr[index] = value
// if(resArr.length ===promiseArr.length) 在某些时刻不正确,比如数组最后一项先执行完 数组就为[empty,empty,value]
if (++idx === promiseArr.length) {
resolve(resArr)
}
}
}
static allSettled(promiseArr) {
let resArr = [],
idx = 0
if (!isIterable(promiseArr)) {
throw new TypeError(`${promiseArr} is not a iterable`)
}
return new Promise((resolve, reject) => {
if (promiseArr.length === 0) {
resolve([])
}
promiseArr.forEach((promise, index) => {
if (isPromise(promise)) {
promise.then(
(value) => {
formatResArr('fulfilled', promise, index, resolve)
},
(reason) => {
formatResArr('rejected', reason, index, resolve)
},
)
} else {
//普通值
formatResArr('fulfilled', promise, index, resolve)
}
})
})
function formatResArr(status, value, index, resolve) {
switch (status) {
case 'fulfilled':
resArr[index] = {
status,
value,
}
break
case 'rejected':
resArr[index] = {
status,
reason: value,
}
break
default:
break
}
if (++idx === promiseArr.length) {
resolve(resArr)
}
}
}
static race(promiseArr) {
if (!isIterable(promiseArr)) {
let type = typeof promiseArr
throw TypeError(`${type} is not a iterable (cannot read property Symbol(Symbol.iterator))
at Function.all (<anonymous>)`)
}
return new Promise((resolve, reject) => {
promiseArr.forEach((promise) => {
if (isPromise(promise)) {
promise.then(resolve, reject)
} else {
resolve(promise)
}
})
})
}
}
function isPromise(x) {
if ((typeof x === 'object' && x !== null) || typeof x === 'function') {
let then = x.then
return typeof then === 'function'
}
return false
}
function isIterable(value) {
return (
value !== null &&
value !== undefined &&
typeof value[Symbol.iterator] === 'function'
)
}
// MyPromise.defer = MyPromise.deferred = function () {
// let dfd = {}
// dfd.promise = new MyPromise((resolve, reject) => {
// dfd.resolve = resolve
// dfd.reject = reject
// })
// return dfd
// }
// module.exports = MyPromise
6.v8 引擎下的 promise
Promise.resolve()
.then(() => {
console.log(0)
return Promise.resolve(4)
})
.then((res) => {
console.log(res)
})
Promise.resolve()
.then(() => {
console.log(1)
})
.then(() => {
console.log(2)
})
.then(() => {
console.log(3)
})
.then(() => {
console.log(5)
})
.then(() => {
console.log(6)
})
// 0 1 2 3 4 5 6
Promise.resolve()
.then(() => {
console.log(0)
return Promise.resolve(4)
})
.then((res) => {
console.log(res)
})
Promise.resolve()
.then(() => {
console.log(1)
})
.then(() => {
console.log(2)
})
.then(() => {
console.log(3)
})
.then(() => {
console.log(5)
})
.then(() => {
console.log(6)
})
// 0 1 2 3 4 5 6
new Promise((resolve, reject) => {
Promise.resolve().then(() => {
resolve({
then: (resolve, reject) => resolve(1),
})
Promise.resolve().then(() => console.log(2))
})
}).then((v) => console.log(v))
// 2 1
new Promise((resolve, reject) => {
Promise.resolve().then(() => {
resolve({
then: (resolve, reject) => resolve(1),
})
Promise.resolve().then(() => console.log(2))
})
}).then((v) => console.log(v))
// 2 1
回顾 PromsieA+对于 then 方法回调函数的返回值的规范描述
如果 then 方法回调函数的返回值是一个 promise 则直接确定好状态(pending,fulfilled,rejected),并且将值确定,
如果 x 是一个对象或者函数,然后看它有没有 then 这个属性,且这个属性是一个函数,如果是则认为它是一个 promise(里面已经很难判断了),并且在访问 then 的时候可能 then 被提前定义(Object.defineproperty(x,'then',{throw new Error}) 所以加上 try catch ,抛出错误则直接 reject 出去