功能清单:
- Promise.prototype.then()
- Promise.prototype.catch()
- Promise.reject()
- Promise.resolve()
- Promise.all()
- Promise.race()
- Promise.prototype.finally()
具体实现
function Promise(fn) {
var _this = this;
var callback = null;
this._value = null; // 存放 $A 的resolve(解决)的结果
this._reason = null; // 存放 $A 的reject(拒绝)的原因
this._thenCallbacks = []; // 存放resolve前调用then时传入的函数(可能多次调用then,所以是数组)
this._catchCallbacks = []; // 存放reject前调用catch时传入的函数(可能多次调用catch,所以是数组)
this._status = "pending";
function onResolved(val) {
if (_this._status !== 'pending') { // 若status已经改变为"resolved"或"rejected",回调在then内处理
return
}
setTimeout(function () {
// 确保回调是异步执行的的
_this._value = val;
_this._status = "resolved";
while (callback = _this._thenCallbacks.shift()) { // 按注册顺序依次执行回调
callback(val)
}
}, 0);
}
function onRejected(reason) {
if (_this._status !== 'pending') {
return
}
setTimeout(function () {
_this._reason = reason;
_this._status = "rejected";
while (callback = _this._catchCallbacks.shift()) {
callback(reason)
}
}, 0);
}
fn(onResolved, onRejected);
}
重点
Promise.prototype.then = function (onResolved, onRejected) {
var _this = this // 本次Promise(命名为$A)
return new Promise(function (resolve, reject) { /* then始终返回一个Promise(命名为$B),用于链式调用: new Promise( ... ).then( ... ).then( ... ) */
function resolveHandle(value) { // 属于 $A
var ret = (typeof onResolved === "function" && onResolved(value)) || value;
if (ret && ret instanceof Promise) { // 如果 ret为Promise实例(命名为$C)
ret.then(function (value) {
resolve(value); // 调用$B的resolve, 将 $C 的结果值传给 $B,也就是说下一个then中的回调可以获取到 $C 的结果值
}, function (reason) {
reject(reason)
});
} else { 如果 ret 不是为Promise实例
resolve(ret); // 调用$B的resolve, 将 ret 传给 $B,也就是说下一个then中的回调可以获取到ret
}
}
function rejectHandle(reason) { // 属于 $A
var err = (typeof onRejected === "function" && onRejected(reason)) || reason;
reject(err); // 调用$B的reject
}
if (_this._status === "pending") {
// resolve或reject前调用then
_this._thenCallbacks.push(resolveHandle);
_this._catchCallbacks.push(rejectHandle);
} else if (_this._status === "resolved") {
// 状态改变后的then操作,立刻执行
resolveHandle(_this._value)
} else if (_this._status === "rejected") {
rejectHandle(_this._reason);
}
});
};
Promise.prototype.catch = function (onRejected) {
return this.then(undefined, onRejected)
}
Promise.resolve = function (value) {
return new Promise(function (resolve, reject) {
resolve(value)
})
}
Promise.reject = function (reason) {
return new Promise(function (resolve, reject) {
reject(reason)
})
}
Promise.all = function (promises) {
if (!Array.isArray(promises)) {
throw new TypeError('必须传入promise数组');
}
var length = promises.length
var values = []
return new Promise(function (resolve, reject) {
function rejectHandle(reason) {
reject(reason) // 只要其中一个reject,整体reject
}
function resolveHandle(index) {
return function (value) {
values[index] = value // 按传入时的顺序记录每个promise的结果值
if (--length === 0) { // 所有子promise都resolve后,整体resolve
resolve(values)
}
}
}
promises.forEach(function (item, index) {
item.then(resolveHandle(index), rejectHandle)
})
})
}
Promise.race = function (promises) {
if (!Array.isArray(promises)) {
throw new TypeError('必须传入promise数组');
}
return new Promise(function (resolve, reject) {
function rejectHandle(reason) {
reject(reason)
}
function resolveHandle(value) {
resolve(value)
}
promises.forEach(function (item) {
item.then(resolveHandle, rejectHandle)
})
})
}
// 不管resolved还是rejected,都会执行,避免同样的语句需要在then()和catch()中各写一次的情况。
Promise.prototype.finally = function (callback) {
return this.then(callback, callback)
}
使用 UMD 规范封装:
(function (global, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(factory)
} else if (typeof exports === 'object' && typeof module !== 'undefined') {
// CommonJS (如node)
module.exports = factory()
} else {
// 浏览器全局变量
global.promisePolyfill = factory()
}
})(this, function () {
'use strict';
/*
定义Promise的代码
*/
function promisePolyfill () {
var global = null
try {
global = Function('return this')();
} catch (e) {
throw new Error('全局对象不可用');
}
global.Promise = Promise
}
return promisePolyfill
})
使用
promisePolyfill() // 注册Promise全局变量
Prmoises A+规范