共计 11648 个字符,预计需要花费 30 分钟才能阅读完成。
关注前端小讴,浏览更多原创技术文章
回顾:Promise 源码渐进式解读(一)
回顾:Promise 源码渐进式解读(二)
回顾:Promise 源码渐进式解读(三)
回顾:Promise 源码渐进式解读(四)
残缺代码 + 正文,可对照浏览
Promise
源码解读系列的最初 1 篇,详解 Promise
构造函数的最初几个办法及 .finally
,封装isArray
判断对象是否为数组:
/* isArray 办法:判断对象是否为数组 */
function isArray(x) {return Boolean(x && typeof x.length !== 'undefined')
}
Promise.all – 源码
/** Promise 构造函数的 all 属性,指向函数
* 参数 arr:数组
*/
Promise.all = function (arr) {
// 返回一个新期约
return new Promise(function (resolve, reject) {if (!isArray(arr)) {return reject(new TypeError('Promise.all accepts an array')) // 参数必须是数组
}
var args = Array.prototype.slice.call(arr) // Array 原型的 slice 办法,利用 call 绑定给 arr(防止有自定义的 slice 办法)if (args.length === 0) return resolve([]) // 若数组长度为 0,则立刻执行执行器函数并返回,参数为空数组
// ↑相当于:new Promise((resolve, reject) => resolve([]))
var remaining = args.length
/**
* res()办法
* 参数 i:数组下标
* 参数 val:数组项
*/
function res(i, val) {
try {// console.log(args[i], val) // args[i]和 val 最后是一样的
/* 如果该项为对象或函数对象,则对其 then 属性做非凡解决 */
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then
// 如果 then 指向一个函数(val 是 Promise 类型或 thenable 对象),则做解决
if (typeof then === 'function') {/* 将该项的 then 办法体内的 this 指向该项自身,并执行 then()
Promise.prototype.then 本来承受 2 个参数 onFulfilled 和 onRejected,将 function(val){}和 reject 回调别离作为这两个办法传给.then()
-> 创立 Handler 实例(this 指向 then 前的 Promise 实例,即该项自身)-> 调用 handle 办法,依据_state 进行下一步操作
-> 如_state 为 1,则调用 Promise._immediateFn
-> 调用 onFulfilled(即 function(val)),参数为期约的_value 值,即调用 function(self._value)(若_state 为 0,则将 Handler 实例放入 then()前 Promise 实例(该项自身)的_deferrends 数组,同步执行暂停,整端代码执行终止,返回该项,即待定的期约)*/
then.call(
val,
function (val) {res(i, val) // 将期约的_value 值作为 val,再次调用 res 办法
},
reject
)
return
}
}
/* 重写该项:若该项为解决的期约则被重写为其解决值 / 回绝理由,若为非期约则不变 */
args[i] = val
// console.log(args[i], val)
// console.log(args)
/* 若所有的 Promise 都执行结束(没有待定的),则执行执行器函数的 resolve 回调,参数为解决后的数组 */
if (--remaining === 0) {resolve(args) // doResolve()外部的 done 管制着 resolve/reject 办法只执行一次}
} catch (ex) {
/* 只有其中一项出现异常,则全副执行退出,进入 catch 异样解决 */
reject(ex) // doResolve()外部的 done 管制着 resolve/reject 办法只执行一次}
}
/* 循环数组,针对每一项执行 res()办法 */
for (var i = 0; i < args.length; i++) {res(i, args[i])
}
})
}
- 参数 必须是 数组 ,若为 空数组 则等同于
new Promise((resolve, reject) => resolve([]))
- 循环参数数组,若数组项为解决的期约,则被重写为其解决值 / 回绝理由,若为非期约则不变
-
若所有的
Promise
都执行结束(没有待定的),则执行执行器函数的resolve
回调,参数为解决后的数组- 若有待定的期约,则会始终期待,直到执行结束
- 只有其中一项出现异常,则全副执行退出,进入
catch
异样解决
Promise.all – 阶段测试
setTimeout(
console.log,
0,
Promise.all(), // 参数不是数组
/* Promise {_state: 2, _handled: false, _value: 'TypeError: Promise.all accepts an array', _deferreds: null} */
Promise.all([]), // 参数是空数组
/* Promise {_state: 1, _handled: false, _value: [], _deferreds: null } */
new Promise((resolve, reject) => resolve([])), // 等效于 Promise.all([])
Promise.all([1, 2, 3]), // 参数是数组,数组的每项不是 Promise 对象
/* Promise {_state: 1, _handled: false, _value: [ 1, 2, 3], _deferreds: null } */
Promise.all([Promise.resolve(1), Promise.resolve(2), Promise.resolve(3)]), // 参数是数组,数组的每项是解决的 Promise 对象
/* Promise {_state: 1, _handled: false, _value: [ 1, 2, 3], _deferreds: null } */
Promise.all([Promise.resolve(true),
Promise.resolve(true),
Promise.resolve(true),
]),
/* Promise {_state: 1, _handled: false, _value: [true, true, true], _deferreds: null } */
Promise.all([Promise.resolve(1), Promise.reject(2), Promise.resolve(3)]), // 参数是数组,数组中有回绝的 Promise 对象
/* Promise {_state: 2, _handled: false, _value: 2, _deferreds: null} */
Promise.all([Promise.resolve(1), new Promise(() => {}), Promise.resolve(3)]) // 参数是数组,数组中有待定的 Promise 对象
/* Promise {_state: 0, _handled: false, _value: undefined, _deferreds: null} */
)
Promise.race – 源码
/** Promise 构造函数的 race 属性,指向函数
* 参数 arr:数组
*/
Promise.race = function (arr) {
// 返回一个新期约
return new Promise(function (resolve, reject) {if (!isArray(arr)) {return reject(new TypeError('Promise.race accepts an array')) // 参数必须是数组
}
/* 循环数组,针对每一项执行 resolve()和.then()办法(若参数为空数组,则不执行,返回待定的期约)*/
for (var i = 0, len = arr.length; i < len; i++) {
/**
* Promise.resolve()办法
* 参数 arr[i]:数组项
*/
Promise.resolve(arr[i]) // 返回新期约
/* Promise.prototype.then()办法
Promise.prototype.then 本来承受 2 个参数 onFulfilled 和 onRejected,将 fn 的 resolve 和 reject 回调别离作为这两个办法传给.then()
-> 创立 Handler 实例(this 指向 then 前的 Promise 实例,即 Promise.resolve()返回的新期约)-> 调用 handle 办法,依据_state 进行下一步操作
-> 如_state 为 1,则调用 Promise._immediateFn
-> 调用 onFulfilled,参数为期约的_value 值,即调用 function(self._value)
*/
.then(resolve, reject) // doResolve()外部的 done 管制着 resolve/reject 办法只执行一次,因而只有最先落定(解决或回绝)的 Promise 执行了 resolve/reject,前面的 Promise 都不执行}
})
// 以 Promise.race([3, 2, 1])为例,能够简化为 new Promise((resolve,reject)=>{Promise.resolve(3).then(resolve, reject)})
}
- 参数 必须是 数组 ,若为 空数组 则返回待定的期约
- 循环参数数组,按顺序调用
Promise.resolve
,参数为数组项 - 只有最先落定(解决或回绝)的
Promise
,依据其状态执行resolve/reject
,前面的都不执行 -
外围思路比对:
Promise.all
:resolve
数组所有项(如果该项是期约,则用其解决值 / 回绝理由替换)Promise.race
:一一Promise.resolve
数组项(如果返回的期约已解决 / 回绝,则不再Promise.resolve
前面的项)
Promise.race – 阶段测试
setTimeout(
console.log,
0,
Promise.race(), // 参数不是数组
/* Promise {_state: 2, _handled: false, _value: 'TypeError: Promise.race accepts an array', _deferreds: null} */
Promise.race([]), // 参数是空数组
/* Promise {_state: 0, _handled: false, _value: undefined, _deferreds: null} */
Promise.race([3, 2, 1]), // 参数是数组,数组的每项不是 Promise 对象
/* Promise {_state: 1, _handled: false, _value: 3, _deferreds: null} */
Promise.resolve(3), // 等效于 Promise.race([3, 2, 1])
/* Promise {_state: 1, _handled: false, _value: 3, _deferreds: null} */
Promise.race([Promise.resolve(3), Promise.resolve(2), Promise.resolve(1)]), // 参数是数组,最先落定解决的 Promise 对象
/* Promise {_state: 1, _handled: false, _value: 3, _deferreds: null} */
Promise.race([Promise.reject(1), Promise.resolve(2), Promise.resolve(3)]), // 参数是数组,最先落定回绝的 Promise 对象
/* Promise {_state: 2, _handled: false, _value: 1, _deferreds: null}
Possible Unhandled Promise Rejection: 1 */
Promise.race([new Promise(() => {}), Promise.resolve(2), Promise.resolve(1)]) // 参数是数组,最先落定解决的 Promise 对象
/* Promise {_state: 1, _handled: false, _value: 2, _deferreds: null} */
)
Promise.prototype.finally – 源码
/** Promise 原型的 finally 属性,指向函数
* 参数 callback:onFinally 处理程序,在期约无论兑现还是回绝后,最终执行的回调
*/
Promise.prototype['finally'] = function (callback) {// console.log(this, 'finally') // this 指向 finally()前返回的 Promise 实例
// console.log(this.constructor) // constructor 指向 Promise 构造函数
// console.log(this.constructor === Promise) // true
var constructor = this.constructor
/* 调用 Promise.prototype.then()办法,以下文 setTimeout 中的测试为例:-> 创立 Handler 实例(this 指向 finally()前的 Promise 实例),创立新 Promise 实例
-> 调用 handle(),_state 为 1,调用 Promise._immediateFn,调用 onFulfilled,调用后返回 Promise 实例(调用过程见 onFulfilled 外部)-> 调用 resolve(),传入 Handler 实例的 promise 和 onFulfilled 返回值(是一个 Promise 实例),将_state 赋值为 3,_value 赋值为 onFulfilled 返回的 Promise 实例
-> 调用 finale(),其_deferreds 为[],赋为 null 后执行完结
-> 返回.then()外部创立的 Promise 实例:Promise {
_state: 3,
_handled: false,
_value: Promise {
_deferreds: null,
_handled: false,
_state: 1,
_value: 2,
}
_deferreds: null
}
*/
return this.then(
/* onFulfilled 处理程序 */
function (value) {
/* 调用过程,以下文 setTimeout 中的测试为例:-> 调用 callback,打印 finally3,返回 3
-> 调用 Promise.resolve(),创立解决的 Promise 实例,解决值为 callback 返回值 3
此时 then 前的 Promise 实例为:Promise {_state: 1, _handled: false, _value: 3, _deferreds: null}
-> 调用.then()(外部 this 指向 Promise.resolve()返回的期约,_state 为 1,_value 为 3),创立 Handler 实例(只有 onFulfilled),创立新 Promise 实例
-> 调用 handle(),外部 state 为 1,将 handled 置为 true,调用 Promise._immediateFn,调用 onFulfilled(即:function() {return value}),返回的 value 是 finally 前 Promise 实例的_value,即 2
-> 调用 resolve(),传入 Handler 实例的 promise 和 onFulfilled 返回值 2,将_state 赋值为 1,_value 赋值为 2
-> 调用 finale(),其_deferreds 为[],赋为 null 后执行完结
-> 返回.then()外部创立的 Promise 实例(作为参数,传递给下层 resolve()办法)返回的 Promise 实例为:Promise {_state: 1, _handled: false, _value: 2, _deferreds: null}
*/
// return constructor.resolve(callback())
return constructor.resolve(callback()).then(function () {// console.log(value) // finally()前返回的 Promise 实例的解决值
return value
})
},
/* onRejected 处理程序 */
function (reason) {return constructor.resolve(callback()).then(function () {// console.log(reason) // finally()前返回的 Promise 实例的回绝理由
return constructor.reject(reason) // 与 onFulfilled 不同的是,外部返回回绝的期约,回绝理由为 finally()前 Promise 实例的回绝理由
/*
Promise._immediateFn 最初一步均为调用 resolve()办法,第二个参数若不是期约,则_state 值会在 resolve()中被赋为 1
因而为了辨别与 onFulfilled 的区别,返回回绝的期约(而不是回绝理由),第二个参数是期约,_state 值在 resolve()中被赋为 3
因而最终返回的期约,会多嵌套一层 Promise(onFulfilled 嵌套 2 层,onRejected 嵌套 3 层),最内层为这个回绝的期约
Promise {
_state: 3,
_handled: false,
_value: Promise {
_deferreds: null,
_handled: false,
_state: 3,
_value: Promise { // 最内层为回绝的期约
_deferreds: null,
_handled: false,
_state: 2, // 此处的_state
_value: 2
}
}
_deferreds: null
}
*/
})
}
/* 内层 Promise 实例赋给外层 Promise 实例的_value,逐层顺次赋值递推 */
)
}
Promise.prototype.finally – 阶段测试
setTimeout(
console.log,
0,
Promise.resolve(2).finally(() => {console.log('finally3') // 打印 'finally3'
return 3
})
/* Promise 为
Promise {
_state: 3,
_handled: false,
_value: Promise {
_state: 0,
_handled: false,
_value: undefined,
_deferreds: null
},
_deferreds: null
}
*/
Promise.reject(2).finally(() => {console.log('finally4') // 打印 'finally4'
return 4
})
/* Promise 为
Promise {
_state: 3,
_handled: false,
_value: Promise {
_state: 3,
_handled: false,
_value: Promise {
_state: 2,
_handled: false,
_value: 2,
_deferreds: null
},
_deferreds: null
},
_deferreds: null
}
*/
)
Promise.allSettled – 源码
/** Promise 构造函数的 allSettled 属性,指向函数
* 参数 arr:数组
*/
Promise.allSettled = function (arr) {// console.log(this) // this 指向 Promise 构造函数
var P = this
// 返回一个新期约
return new P(function (resolve, reject) {
// 参数必须是数组
if (!(arr && typeof arr.length !== 'undefined')) {
return reject(
new TypeError(
typeof arr +
' ' +
arr +
'is not iterable(cannot read property Symbol(Symbol.iterator))'
)
)
}
var args = Array.prototype.slice.call(arr) // Array 原型的 slice 办法,利用 call 绑定给 arr(防止有自定义的 slice 办法)if (args.length === 0) return resolve([]) // 若数组长度为 0,则立刻执行执行器函数并返回,参数为空数组
// ↑相当于:new Promise((resolve, reject) => resolve([]))
var remaining = args.length
/**
* res()办法
* 参数 i:数组下标
* 参数 val:数组项
*/
function res(i, val) {// console.log(args[i], val) // args[i]和 val 最后是一样的
/* 如果该项为对象或函数对象,则对其 then 属性做非凡解决 */
if (val && (typeof val === 'object' || typeof val === 'function')) {
var then = val.then
// 如果 then 指向一个函数(val 是 Promise 类型或 thenable 对象),则做解决
if (typeof then === 'function') {/* 将该项的 then 办法体内的 this 指向该项自身,并执行 then()
Promise.prototype.then 本来承受 2 个参数 onFulfilled 和 onRejected,将 function(val){}和 function(e){}回调别离作为这两个办法传给.then()
-> 创立 Handler 实例(this 指向 then 前的 Promise 实例,即该项自身)-> 调用 handle 办法,依据_state 进行下一步操作
-> 如_state 为 1,则调用 Promise._immediateFn
-> 调用 onFulfilled(即 function(val)),参数为期约的_value 值,即调用 function(self._value)(若_state 为 0,则将 Handler 实例放入 then()前 Promise 实例(该项自身)的_deferrends 数组,同步执行暂停,整端代码执行终止,返回该项,即待定的期约)*/
then.call(
val,
function (val) {res(i, val) // 将期约的_value 值作为 val,再次调用 res 办法
},
function (e) {args[i] = {status: 'rejected', reason: e} // 将该项重写为{status:'rejected',reason: 谬误起因}
/* 若所有的项都执行结束,则执行执行器函数的 resolve 回调,参数为解决后的数组 */
if (--remaining === 0) {resolve(args)
}
}
)
return
}
}
/* 重写该项:若该项为解决的期约,则被重写为{status:'fulfilled',value: 解决值}
若该项为回绝的期约,则被重写为{status:'rejected',reason: 回绝理由}
若该项为非期约,则被重写为对象{status:'fulfilled',value: 该项}
*/
args[i] = {status: 'fulfilled', value: val}
// console.log(args[i], val)
// console.log(args)
/* 若所有的 Promise 都执行结束(没有待定的),则执行执行器函数的 resolve 回调,参数为解决后的数组 */
if (--remaining === 0) {resolve(args) // doResolve()外部的 done 管制着 resolve/reject 办法只执行一次}
}
/* 循环数组,针对每一项执行 res()办法 */
for (var i = 0; i < args.length; i++) {res(i, args[i])
}
})
}
- 参数 必须是 数组 ,若为 空数组 则等同于
new Promise((resolve, reject) => resolve([]))
-
循环参数数组,并重写:
- 若该项为 解决的期约,则被重写为
{status:'fulfilled',value: 解决值}
- 若该项为 回绝的期约,则被重写为
{status:'rejected',reason: 回绝理由}
- 若该项为 非期约,则被重写为对象
{status:'fulfilled',value: 该项}
- 若该项为 解决的期约,则被重写为
-
若所有的
Promise
都执行结束(没有待定的),则执行执行器函数的resolve
回调,参数为解决后的数组- 若有待定的期约,则会始终期待,直到执行结束
Promise.allSettled – 阶段测试
setTimeout(
console.log,
0,
Promise.allSettled(), // 参数不是数组
/* Promise {_state: 2, _handled: false, _value: 'TypeError: undefined undefined is not iterable(cannot read property Symbol(Symbol.iterator))', _deferreds: null } */
Promise.allSettled([]), // 参数是空数组
/* Promise {_state: 1, _handled: false, _value: [], _deferreds: null } */
Promise.allSettled([3, 2, 1]), // 参数是数组,数组的每项都不是 Promise 对象
/*
Promise {
_state: 1,
_handled: false,
_value: [{ status: 'fulfilled', value: 3},
{status: 'fulfilled', value: 2},
{status: 'fulfilled', value: 1}
],
_deferreds: null
}
*/
Promise.allSettled([Promise.resolve(3),
Promise.resolve(2),
Promise.resolve(1),
]), // 参数是数组,每项都是解决的 Promise 对象
/*
Promise {
_state: 1,
_handled: false,
_value: [{ status: 'fulfilled', value: 3},
{status: 'fulfilled', value: 2},
{status: 'fulfilled', value: 1}
],
_deferreds: null
}
*/
Promise.allSettled([Promise.resolve(1),
Promise.reject(2),
Promise.resolve(3),
]), // 参数是数组,每项都是 Promise 对象,有回绝的期约
/*
Promise {
_state: 1,
_handled: false,
_value: [{ status: 'fulfilled', value: 1},
{status: 'rejected', reason: 2},
{status: 'fulfilled', value: 3}
],
_deferreds: null
}
*/
Promise.allSettled([Promise.resolve(2),
new Promise(() => {}),
Promise.resolve(1),
]) // 参数是数组,每项都是 Promise 对象,有待定的期约
/* Promise {_state: 0, _handled: false, _value: undefined, _deferreds: [] } */
)
实现后果总结
- 实现
Promise
构造函数办法:Promise,all
、Promise.race
、Promise.allSettled
- 实现
Promise
原型办法:Promise.prototype.finally
截至本节的代码 →
正文完