# Promise 构造函数
Promise 构造函数需要传的参数就是一个 executor 构造器函数。executor 里需要传 resolve 和 reject 函数,用于改变 Promise 实例的状态
- 功能:立即执行 executor 代码,并且传递出两个函数用于改变 Promise 实例状态
- 参数:resolve 函数和 reject 函数
- 返回值:无
// 定义状态 | |
const PENDING = 'pending'; | |
const FULFILLED = 'fulfilled'; | |
const REJECTED = 'rejected'; | |
function Promise(executor){ | |
const that = this; // 保证 this 指向实例 | |
this.status = PENDING; // 初始化状态 | |
this.data = undefined; // 保存成功或失败回调的值 | |
this.callbacks = []; // 保存回调队列,用 {onResolve,onReject} 对象存储指定的回调函数队列 | |
// 更改实例状态为成功的函数 | |
function resolve(value){ | |
// 判定当前状态是否为 pending,若不是则不允许第二次更改状态 | |
if(that.status !== PENDING) return ; | |
// 将实例状态更改为 fulfilled 并保存传入的 value | |
that.status = FULFILLED; | |
that.data = value; | |
// 检查回调队列有没有回调函数需要调用 | |
if (that.callbacks.length > 0) { | |
// 将成功回调推入微队列异步执行 | |
queueMicrotask(() => { | |
that.callbacks.forEach(cb => cb.onResolve(that.data)); | |
}); | |
} | |
} | |
// 更改实例状态为失败的函数 | |
function reject(reason){ | |
// 判定当前状态是否为 pending,若不是则不允许第二次更改状态 | |
if(that.status !== PENDING) return ; | |
// 将实例状态更改为 rejected 并保存传入的 reason | |
that.status = REJECTED; | |
that.data = reason; | |
// 检查回调队列有没有回调函数需要调用 | |
if (that.callbacks.length > 0) { | |
// 将失败回调推入微队列异步执行 | |
queueMicrotask(() => { | |
that.callbacks.forEach(cb => cb.onResolve(that.data)); | |
}); | |
} | |
} | |
// 同步执行 executor,并向外传递出改变实例状态的函数 | |
executor(resolve,reject); | |
} |
# Promise.prototype.then()
- 功能:给实例对象指定成功和失败的回调
- 参数:成功的回调函数和失败的回调函数
- 返回值:return 一个新的 Promise 实例
- 特性:return 的 Promise 实例状态根据传入回调函数的执行结果决定
- return 的 Promise 状态影响因素
- 回调函数执行抛出异常,return 的新 Promise 状态为 rejected,reason 为该异常
- 回调函数返回非 Promise 值,return 的新 Promise 状态为 fulfilled,value 为回调函数的返回值
- 回调函数返回 Promise 值,return 的新 Promise 状态和值都跟随返回的 Promise
Promise.prototype.then = function(onResolve,onReject){ | |
const that = this; | |
// 判定传入的成功回调是否为函数,若不是则强制改为函数 | |
onResolve = typeof onResolve === 'function' ? onResolve : value => value ; | |
// 判定传入的失败回调是否为函数,若不是则原样抛出异常,实现异常穿透 | |
onReject = typeof onReject === 'function' ? onReject : reason => {throw reason}; | |
return new Promise((resolve,reject)=>{ | |
// 定义 handle 函数处理所有能影响 return 的 Promise 状态的情况 | |
function handle(callback){ | |
//1. 若回调函数执行抛出异常则捕获异常 | |
try{ | |
const res = callback(that.data); // 接收成功回调的返回值 | |
// 判断返回值类型并处理 | |
if(res instanceof Promise){ | |
//3. 根据 res 的状态决定 return 的 Promise 状态 | |
res.then(resolve,reject); | |
}else{ //2. 非 Promise 返回值直接返回 | |
resolve(res); | |
} | |
}catch(error){ | |
reject(error); | |
} | |
} | |
// 若此时是先指定了回调函数,后面改变的状态则将回调放入回调队列 | |
if(that.status === PENDING){ | |
that.callbacks.push( | |
{ | |
onResolve(value){ | |
handle(onResolve); | |
}, | |
onReject(reason){ | |
handle(onReject); | |
} | |
} | |
) | |
}else if(that.status === FULFILLED){ // 若先改变了状态,则直接将回调函数推入微队列执行 | |
queueMicrotask(()=>{ | |
handle(onResolve); | |
}) | |
}else{ | |
queueMicrotask(()=>{ | |
handle(onReject); | |
}) | |
} | |
}) | |
} |
# Promise.prototype.catch()
- 功能:给实例对象指定失败的回调
- 参数:失败的回调函数
- 返回值:return 一个新的 Promise 实例
- 特性:return 的 Promise 实例状态根据传入回调函数的执行结果决定
- return 的 Promise 状态影响因素
- 回调函数执行抛出异常,return 的新 Promise 状态为 rejected,reason 为该异常
- 回调函数返回非 Promise 值,return 的新 Promise 状态为 fulfilled,value 为回调函数的返回值
- 回调函数返回 Promise 值,return 的新 Promise 状态和值都跟随返回的 Promise
Promise.prototype.catch = function(onReject){ | |
return this.then(undefined,onReject); | |
} |
# Promise.resolve()
- 功能:根据传入的 value 返回一个已经改变了状态的 Promise
- 参数:value
- 返回值:return 一个新的 Promise 实例
- 特性:return 的 Promise 实例状态根据传入 value 决定
- return 的 Promise 状态影响因素
2. value 是一个非 Promise,return 的新 Promise 状态为 fulfilled,value 为回调函数的返回值
3. value 是一个 Promise,return 的新 Promise 状态和值都跟随返回的 Promise
// 仅需根据 then 中 handle 函数的逻辑重写一遍即可 | |
Promise.resolve = function(value){ | |
return new Promise((resolve,reject)=>{ | |
if(value instanceof Promise){ | |
value.then(resolve,reject); | |
}else{ | |
resolve(value); | |
} | |
}) | |
} |
# Promise.reject()
- 功能:根据传入的 value 返回一个已经改变了状态的 Promise
- 参数:reason
- 返回值:return 一个新的 rejected 状态的 Promise 实例
- 特性:return 的 Promise 实例状态一定是 rejected
Promise.reject = function(reason){ | |
return new Promise((resolve,reject)=>{ | |
if(reason instanceof Error){ | |
reject(reason.message); | |
}else if(reason instanceof Promise){ | |
reject(reason.data); | |
}else{ | |
reject(reason); | |
} | |
}) | |
} |
# Promise.all()
- 功能:根据传入的 Promise 数组,若该数组的 Promise 最后全都成功则返回一个 fulfilled 的 Promise,否则返回一个 rejected 的 Promise
- 参数:Promise 数组
- 返回值:return 一个 Promise 实例
- 特性:return 的 Promise 实例状态根据传入的 Promise 数组决定
Promise.all = function(promiseArr){ | |
const values = [];// 定义一个 values 保存成功 Promise 的 value 的值 | |
let count = 0; // 记录有几个 Promise 成功 | |
return new Promise((resolve,reject)=>{ | |
// 遍历数组所有元素 | |
promiseArr.forEach((p,index)=>{ | |
Promise.resolve(p).then( // 用 Promise.resolve 包裹,处理数组中有非 Promise 值的情况 | |
value => { | |
++count; | |
values[index] = value; | |
if(count === promiseArr.length) resolve(values); | |
}, | |
reason => reject(reason)) | |
}); | |
}) | |
} |
# Promise.race()
- 功能:根据传入的 Promise 数组,return 的 Promise 状态跟随第一个完成的 Promise
- 参数:Promise 数组
- 返回值:return 一个 Promise 实例
- 特性:return 的 Promise 实例状态跟随第一个完成的 Promise
Promise.race = function(promiseArr){ | |
return new Promise((resolve,reject)=>{ | |
promiseArr.forEach((p)=>{ | |
Promise.resolve(p).then( // 用 Promise.resolve 包裹,处理数组中有非 Promise 值的情况 | |
value => resolve(value), | |
reason => reject(reason) | |
) | |
}) | |
}) | |
} |
# 完整代码
# ES5 版
(function (w) { | |
const PENDING = 'pending'; | |
const FULFILLED = 'fulfilled'; | |
const REJECTED = 'rejected'; | |
function Promise(executor) { | |
const that = this; | |
that.status = PENDING; | |
that.data = undefined; | |
that.callbacks = []; | |
function resolve(value) { | |
if (that.status !== PENDING) return; | |
that.status = FULFILLED; | |
that.data = value; | |
if (that.callbacks.length > 0) { | |
queueMicrotask(() => { | |
that.callbacks.forEach(cb => cb.onResolve(that.data)); | |
}); | |
} | |
}; | |
function reject(reason) { | |
if (that.status !== PENDING) return; | |
that.status = REJECTED; | |
that.data = reason; | |
if (that.callbacks.length > 0) { | |
queueMicrotask(() => { | |
that.callbacks.forEach(cb => cb.onReject(that.data)); | |
}); | |
} | |
}; | |
executor(resolve, reject); | |
}; | |
Promise.prototype.then = function (onResolve, onReject) { | |
const that = this; | |
onResolve = typeof onResolve === 'function' ? onResolve : value => value; | |
onReject = typeof onReject === 'function' ? onReject : reason => { throw reason }; | |
return new Promise((resolve, reject) => { | |
function handle(callback) { | |
try { | |
const res = callback(that.data); | |
if (res instanceof Promise) { | |
res.then(resolve, reject); | |
} else { | |
resolve(res); | |
} | |
} catch (error) { | |
reject(error); | |
} | |
} | |
if (that.status === PENDING) { | |
that.callbacks.push( | |
{ | |
onResolve(value) { | |
handle(onResolve); | |
}, | |
onReject(reason) { | |
handle(onReject); | |
} | |
} | |
) | |
} else if (that.status === FULFILLED) { | |
queueMicrotask(() => { | |
handle(onResolve); | |
}) | |
} else { | |
queueMicrotask(() => { | |
handle(onReject); | |
}) | |
}; | |
}); | |
}; | |
Promise.prototype.catch = function (onReject) { | |
return this.then(undefined, onReject); | |
}; | |
Promise.resolve = function (value) { | |
return new Promise((resolve, reject) => { | |
if (value instanceof Promise) { | |
value.then(resolve, reject); | |
}else { | |
resolve(value); | |
} | |
}) | |
}; | |
Promise.reject = function (reason) { | |
return new Promise((resolve, reject) => { | |
if (reason instanceof Error) { | |
reject(reason.message); | |
} else if (reason instanceof Promise) { | |
reject(reason.data); | |
} else { | |
reject(reason); | |
} | |
}) | |
}; | |
Promise.all = function (promiseArr) { | |
const values = []; | |
let count = 0; | |
return new Promise((resolve, reject) => { | |
promiseArr.forEach((p, index) => { | |
Promise.resolve(p).then( | |
value => { | |
++count; | |
values[index] = value; | |
if (count === promiseArr.length) resolve(values); | |
}, | |
reason => reject(reason)) | |
}); | |
}) | |
}; | |
Promise.race = function (promiseArr) { | |
return new Promise((resolve, reject) => { | |
promiseArr.forEach((p) => { | |
Promise.resolve(p).then( | |
value => resolve(value), | |
reason => reject(reason) | |
) | |
}) | |
}) | |
}; | |
w.Promise = Promise; | |
})(window) |
# ES6 版
(function (w) { | |
const PENDING = 'pending'; | |
const FULFILLED = 'fulfilled'; | |
const REJECTED = 'rejected'; | |
class Promise { | |
constructor(executor) { | |
const that = this; | |
that.status = PENDING; | |
that.data = undefined; | |
that.callbacks = []; | |
function resolve(value) { | |
if (that.status !== PENDING) return; | |
that.status = FULFILLED; | |
that.data = value; | |
if (that.callbacks.length > 0) { | |
queueMicrotask(() => { | |
that.callbacks.forEach(cb => cb.onResolve(that.data)); | |
}); | |
} | |
} | |
function reject(reason) { | |
if (that.status !== PENDING) return; | |
that.status = REJECTED; | |
that.data = reason; | |
if (that.callbacks.length > 0) { | |
queueMicrotask(() => { | |
that.callbacks.forEach(cb => cb.onReject(that.data)); | |
}); | |
} | |
} | |
executor(resolve, reject); | |
}; | |
then(onResolve, onReject) { | |
const that = this; | |
onResolve = typeof onResolve === 'function' ? onResolve : value => value; | |
onReject = typeof onReject === 'function' ? onReject : reason => { throw reason }; | |
return new Promise((resolve, reject) => { | |
function handle(callback) { | |
try { | |
const res = callback(that.data); | |
if (res instanceof Promise) { | |
res.then(resolve, reject); | |
} else { | |
resolve(res); | |
} | |
} catch (error) { | |
reject(error); | |
} | |
} | |
if (that.status === PENDING) { | |
that.callbacks.push( | |
{ | |
onResolve(value) { | |
handle(onResolve); | |
}, | |
onReject(reason) { | |
handle(onReject); | |
} | |
} | |
) | |
} else if (that.status === FULFILLED) { | |
queueMicrotask(() => { | |
handle(onResolve); | |
}) | |
} else { | |
queueMicrotask(() => { | |
handle(onReject); | |
}) | |
}; | |
}); | |
}; | |
catch(onReject) { | |
return this.then(undefined, onReject); | |
}; | |
static resolve(value) { | |
return new Promise((resolve, reject) => { | |
if (value instanceof Promise) { | |
value.then(resolve, reject); | |
}else { | |
resolve(value); | |
} | |
}) | |
}; | |
static reject(reason) { | |
return new Promise((resolve, reject) => { | |
if (reason instanceof Error) { | |
reject(reason.message); | |
} else if (reason instanceof Promise) { | |
reject(reason.data); | |
} else { | |
reject(reason); | |
} | |
}) | |
}; | |
static all(promiseArr) { | |
const values = []; | |
let count = 0; | |
return new Promise((resolve, reject) => { | |
promiseArr.forEach((p, index) => { | |
Promise.resolve(p).then( | |
value => { | |
++count; | |
values[index] = value; | |
if (count === promiseArr.length) resolve(values); | |
}, | |
reason => reject(reason)) | |
}); | |
}) | |
}; | |
static race(promiseArr) { | |
return new Promise((resolve, reject) => { | |
promiseArr.forEach((p) => { | |
Promise.resolve(p).then( | |
value => resolve(value), | |
reason => reject(reason) | |
) | |
}) | |
}) | |
}; | |
} | |
w.Promise = Promise; | |
})(window) |