目录
手写promise
同步版
1.Promise的构造方法接收一个executor(),在new Promise()时就立刻执行executor回调
2.executor()内部的异步任务被放入宏/微任务队列,等待执行
3.状态与结果的管理
状态只能变更一次
4.then()调用成功/失败回调
catch是调用失败回调的简写
异步版
1.缓存成功与失败回调
2.then 增加 Pending处理
3.resolve 与 reject 中调用回调函数
多次调用同一个promise的then
1.缓存成功与失败回调 队列
2.pengding时,then()收集依赖,将成功/失败回调放入成功/失败队列
3.触发resolve/reject,从成功/失败队列中取出回调依次执行
then链式调用:返回一个 Promise 对象
then返回自己时,抛错循环调用
等返回的promise初始化好:queueMicrotask微任务
捕获错误
executor错误
then错误
then([onFulfilled, onRejected])参数可选
then 穿透:忽略非函数参数,非函数会同步执行
静态调用resolve、reject
完整版
Promise A+ 规范版的resolvePromise
catch
finally
并发请求
模板
all
allSettled
any
race
手写promise
同步版
1.将promise的resolve和reject函数传给实例用
constructor(executor){// executor 是一个执行器,进入会立即执行// 并传入resolve和reject方法executor(this.resolve, this.reject) }
2.实例给resolve和reject函数传值
resolve('success') reject('err')
// 新建 test.js// 引入我们的 MyPromise.js
const MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {resolve('success')reject('err')
})promise.then(value => {console.log('resolve', value)
}, reason => {console.log('reject', reason)
})// 执行结果:resolve success
1.Promise
的构造方法接收一个executor()
,在new Promise()
时就立刻执行executor回调
class Promise{// 构造方法接收一个回调constructor(executor){executor();}
2.executor()
内部的异步任务被放入宏/微任务队列,等待执行
// resolve和reject为什么要用箭头函数?
// 如果直接调用的话,普通函数this指向的是window或者undefined
// 用箭头函数就可以让this指向当前实例对象
class MyPromise {constructor(executor){// executor 是一个执行器,进入会立即执行// 并传入resolve和reject方法executor(this.resolve, this.reject) }// 更改成功后的状态resolve = () => {}// 更改失败后的状态reject = () => {}
}
3.状态与结果的管理
状态只能变更一次
// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';// 新建 MyPromise 类
class MyPromise {constructor(executor){...}// 储存状态的变量,初始值是 pendingstatus = PENDING;// 成功之后的值value = null;// 失败之后的原因reason = null;// 更改成功后的状态resolve = (value) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态修改为成功this.status = FULFILLED;// 保存成功之后的值this.value = value;}}// 更改失败后的状态reject = (reason) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态成功为失败this.status = REJECTED;// 保存失败后的原因this.reason = reason;}}
}
4.then()调用
成功/失败回调
catch
是调用
失败回调的简写
// MyPromise.jsthen(onFulfilled, onRejected) {// 判断状态if (this.status === FULFILLED) {// 调用成功回调,并且把值返回onFulfilled(this.value);} else if (this.status === REJECTED) {// 调用失败回调,并且把原因返回onRejected(this.reason);}
}
异步版
// test.jsconst MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {setTimeout(() => {resolve('success')}, 2000);
})promise.then(value => {console.log('resolve', value)
}, reason => {console.log('reject', reason)
})// 同步版没有打印信息(执行到then时,状态还是pending)
// 异步版等待 2s 输出 resolve success
1.缓存成功与失败回调
// MyPromise 类中新增
// 存储成功回调函数
onFulfilledCallback = null;
// 存储失败回调函数
onRejectedCallback = null;
2.then 增加 Pending处理
// MyPromise.jsthen(onFulfilled, onRejected) {...if (this.status === PENDING) {// ==== 新增 ====// 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来// 等到执行成功失败函数的时候再传递this.onFulfilledCallback = onFulfilled;this.onRejectedCallback = onRejected;}
}
3.resolve 与 reject 中调用回调函数
// MyPromise.js// 更改成功后的状态
resolve = (value) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态修改为成功this.status = FULFILLED;// 保存成功之后的值this.value = value;// ==== 新增 ====// 判断成功回调是否存在,如果存在就调用this.onFulfilledCallback && this.onFulfilledCallback(value);}
}
多次调用同一个promise的then
// test.jsconst MyPromise = require('./MyPromise')
const promise = new MyPromise((resolve, reject) => {setTimeout(() => {resolve('success')}, 2000);
})promise.then(value => {console.log(1)console.log('resolve', value)
})promise.then(value => {console.log(2)console.log('resolve', value)
})promise.then(value => {console.log(3)console.log('resolve', value)
})
//单个回调:3
resolve success
//回调队列:
1
resolve success
2
resolve success
3
resolve success
1.缓存成功与失败回调 队列
// MyPromise.js// 存储成功回调函数
// onFulfilledCallback = null;
onFulfilledCallbacks = [];
// 存储失败回调函数
// onRejectedCallback = null;
onRejectedCallbacks = [];
2.pengding时,then()收集依赖
,将成功/失败回调放入成功/失败队列
// MyPromise.jsthen(onFulfilled, onRejected) {// 判断状态if (this.status === FULFILLED) {// 调用成功回调,并且把值返回onFulfilled(this.value);} else if (this.status === REJECTED) {// 调用失败回调,并且把原因返回onRejected(this.reason);} else if (this.status === PENDING) {// ==== 新增 ====// 因为不知道后面状态的变化,这里先将成功回调和失败回调存储起来// 等待后续调用this.onFulfilledCallbacks.push(onFulfilled);this.onRejectedCallbacks.push(onRejected);}
}
3.
触发resolve/reject
,从成功/失败队列中取出回调依次执行
// MyPromise.js// 更改成功后的状态
resolve = (value) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态修改为成功this.status = FULFILLED;// 保存成功之后的值this.value = value;// ==== 新增 ====// resolve里面将所有成功的回调拿出来执行while (this.onFulfilledCallbacks.length) {// Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空this.onFulfilledCallbacks.shift()(value)}}
}
then链式调用:返回一个 Promise 对象
以fulfilled为例,其他同理
// MyPromise.jsclass MyPromise {...then(onFulfilled, onRejected) {// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去const promise2 = new MyPromise((resolve, reject) => {// 这里的内容在执行器中,会立即执行if (this.status === FULFILLED) {// 获取成功回调函数的执行结果const x = onFulfilled(this.value);// 传入 resolvePromise 集中处理resolvePromise(x, resolve, reject);} ...}) return promise2;}
}function resolvePromise(x, resolve, reject) {// 判断x是不是 MyPromise 实例对象if(x instanceof MyPromise) {// 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected// x.then(value => resolve(value), reason => reject(reason))// 简化之后x.then(resolve, reject)} else{// 普通值resolve(x)}
}
then返回自己时,抛错循环调用
// test.jsconst promise = new Promise((resolve, reject) => {resolve(100)
})
const p1 = promise.then(value => {console.log(value)return p1
})
function resolvePromise(promise2, x, resolve, reject) {// 如果相等了,说明return的是自己,抛出类型错误并返回if (promise2 === x) {return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}...
}
等返回的promise初始化好:queueMicrotask微任务
// MyPromise.jsclass MyPromise {......then(onFulfilled, onRejected) {const promise2 = new MyPromise((resolve, reject) => {if (this.status === FULFILLED) {// 创建一个微任务等待 promise2 完成初始化queueMicrotask(() => {// 获取成功回调函数的执行结果const x = onFulfilled(this.value);// 传入 resolvePromise 集中处理resolvePromise(promise2, x, resolve, reject);}) } ...}) return promise2;}
}
捕获错误
try {异步操作
} catch (error) {reject(error)
}
executor错误
// MyPromise.jsconstructor(executor){// ==== 新增 ====// executor 是一个执行器,进入会立即执行// 并传入resolve和reject方法try {executor(this.resolve, this.reject)} catch (error) {// 如果有错误,就直接执行 rejectthis.reject(error)}
}
then错误
// MyPromise.jsthen(onFulfilled, onRejected) {// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去const promise2 = new MyPromise((resolve, reject) => {// 判断状态if (this.status === FULFILLED) {// 创建一个微任务等待 promise2 完成初始化queueMicrotask(() => {try {// 获取成功回调函数的执行结果const x = onFulfilled(this.value);// 传入 resolvePromise 集中处理resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error)} }) } ...}) return promise2;
}
then([onFulfilled, onRejected])参数可选
then 穿透:忽略非函数参数,非函数会同步执行
Promise.resolve(1).then(2)//传入值.then(Promise.resolve(3))//传入promise对象.then(console.log)//传入函数
1
Promise.resolve().then(new Promise(r => {setTimeout(() => {r(console.log(1))}, 1000)})).then(new Promise(r => {setTimeout(() => {r(console.log(2))}, 1000)})).then(new Promise(r => {setTimeout(() => {r(console.log(3))}, 1000)}))
延迟1秒后,打印123
不同于下面
// MyPromise.jsthen(onFulfilled, onRejected) {// 如果不传,就使用默认函数onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;onRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去const promise2 = new MyPromise((resolve, reject) => {......
}
静态调用resolve、reject
// MyPromise.jsMyPromise {......// resolve 静态方法static resolve (parameter) {// 如果传入 MyPromise 就直接返回if (parameter instanceof MyPromise) {return parameter;}// 转成常规方式return new MyPromise(resolve => {resolve(parameter);});}// reject 静态方法static reject (reason) {return new MyPromise((resolve, reject) => {reject(reason);});}
}
完整版
// MyPromise.js// 先定义三个常量表示状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';// 新建 MyPromise 类
class MyPromise {constructor(executor){// executor 是一个执行器,进入会立即执行// 并传入resolve和reject方法try {executor(this.resolve, this.reject)} catch (error) {this.reject(error)}}// 储存状态的变量,初始值是 pendingstatus = PENDING;// 成功之后的值value = null;// 失败之后的原因reason = null;// 存储成功回调函数onFulfilledCallbacks = [];// 存储失败回调函数onRejectedCallbacks = [];// 更改成功后的状态resolve = (value) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态修改为成功this.status = FULFILLED;// 保存成功之后的值this.value = value;// resolve里面将所有成功的回调拿出来执行while (this.onFulfilledCallbacks.length) {// Array.shift() 取出数组第一个元素,然后()调用,shift不是纯函数,取出后,数组将失去该元素,直到数组为空this.onFulfilledCallbacks.shift()(value)}}}// 更改失败后的状态reject = (reason) => {// 只有状态是等待,才执行状态修改if (this.status === PENDING) {// 状态成功为失败this.status = REJECTED;// 保存失败后的原因this.reason = reason;// resolve里面将所有失败的回调拿出来执行while (this.onRejectedCallbacks.length) {this.onRejectedCallbacks.shift()(reason)}}}then(onFulfilled, onRejected) {const realOnFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;const realOnRejected = typeof onRejected === 'function' ? onRejected : reason => {throw reason};// 为了链式调用这里直接创建一个 MyPromise,并在后面 return 出去const promise2 = new MyPromise((resolve, reject) => {const fulfilledMicrotask = () => {// 创建一个微任务等待 promise2 完成初始化queueMicrotask(() => {try {// 获取成功回调函数的执行结果const x = realOnFulfilled(this.value);// 传入 resolvePromise 集中处理resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error)} }) }const rejectedMicrotask = () => { // 创建一个微任务等待 promise2 完成初始化queueMicrotask(() => {try {// 调用失败回调,并且把原因返回const x = realOnRejected(this.reason);// 传入 resolvePromise 集中处理resolvePromise(promise2, x, resolve, reject);} catch (error) {reject(error)} }) }// 判断状态if (this.status === FULFILLED) {fulfilledMicrotask() } else if (this.status === REJECTED) { rejectedMicrotask()} else if (this.status === PENDING) {// 等待// 因为不知道后面状态的变化情况,所以将成功回调和失败回调存储起来// 等到执行成功失败函数的时候再传递this.onFulfilledCallbacks.push(fulfilledMicrotask);this.onRejectedCallbacks.push(rejectedMicrotask);}}) return promise2;}// resolve 静态方法static resolve (parameter) {// 如果传入 MyPromise 就直接返回if (parameter instanceof MyPromise) {return parameter;}// 转成常规方式return new MyPromise(resolve => {resolve(parameter);});}// reject 静态方法static reject (reason) {return new MyPromise((resolve, reject) => {reject(reason);});}
}function resolvePromise(promise2, x, resolve, reject) {// 如果相等了,说明return的是自己,抛出类型错误并返回if (promise2 === x) {return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}// 判断x是不是 MyPromise 实例对象if(x instanceof MyPromise) {// 执行 x,调用 then 方法,目的是将其状态变为 fulfilled 或者 rejected// x.then(value => resolve(value), reason => reject(reason))// 简化之后x.then(resolve, reject)} else{// 普通值resolve(x)}
}module.exports = MyPromise;
Promise A+ 规范版的resolvePromise
要求判断 x 是否为 object 或者 function,满足则接着判断 x.then 是否存在,这里可以理解为判断 x 是否为 promise,这里都功能实际与我们手写版本中 x instanceof MyPromise
功能相似
// MyPromise.jsfunction resolvePromise(promise, x, resolve, reject) {// 如果相等了,说明return的是自己,抛出类型错误并返回if (promise === x) {return reject(new TypeError('The promise and the return value are the same'));}if (typeof x === 'object' || typeof x === 'function') {// x 为 null 直接返回,走后面的逻辑会报错if (x === null) {return resolve(x);}let then;try {// 把 x.then 赋值给 then then = x.then;} catch (error) {// 如果取 x.then 的值时抛出错误 error ,则以 error 为据因拒绝 promisereturn reject(error);}// 如果 then 是函数if (typeof then === 'function') {let called = false;try {then.call(x, // this 指向 x// 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)y => {// 如果 resolvePromise 和 rejectPromise 均被调用,// 或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用// 实现这条需要前面加一个变量 calledif (called) return;called = true;resolvePromise(promise, y, resolve, reject);},// 如果 rejectPromise 以据因 r 为参数被调用,则以据因 r 拒绝 promiser => {if (called) return;called = true;reject(r);});} catch (error) {// 如果调用 then 方法抛出了异常 error:// 如果 resolvePromise 或 rejectPromise 已经被调用,直接返回if (called) return;// 否则以 error 为据因拒绝 promisereject(error);}} else {// 如果 then 不是函数,以 x 为参数执行 promiseresolve(x);}} else {// 如果 x 不为对象或者函数,以 x 为参数执行 promiseresolve(x);}
}
catch
//catch方法其实就是执行一下then的第二个回调
catch(rejectFn) {return this.then(undefined, rejectFn)
}
finally
由于无法知道promise的最终状态,所以finally
的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况
finally(callBack) {return this.then(callBack, callBack)}
并发请求
模板
/*** @param {iterable} promises 一个promise的iterable类型(注:Array,Map,Set都属于ES6的iterable类型)的输入* @returns */
static 并发(promises) {
// 参数校验
if (Array.isArray(promises)) {let result = []; // 存储结果let count = 0; // 计数器if (promises.length === 0) {
// 如果传入的参数是一个空的可迭代对象,则返回一个已完成(already resolved)状态的 Promisereturn resolve(promises);//C. 返回一个 已失败(already rejected) 状态的 Promise。return reject(new AggregateError('All promises were rejected'));}return new myPromise((resolve, reject) => {promises.forEach((item, index) => {myPromise.resolve(item).then(value => {count++;// 每个promise执行的结果存储在result中//A.记录所有reject/fulfilled,需要区分状态result[index] = {status: 'fulfilled',value}//B.只记录fulfilledresult[index] = value// 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)count === promises.length && resolve(result);//C.只要一个成功resolve(value);},reason => {//A.记录所有rejectcount++;result[index] = {status: 'rejected',reason}count === promises.length && resolve(result);//B.一旦rejectreject(reason); //C.全rejectcount++;errors.push(reason);//AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。count === promises.length && reject(new AggregateError(errors));})})} else {return reject(new TypeError('Argument is not iterable'))
}}
all
/**
* 如果传入的 promise 中有一个失败(rejected),
* Promise.all 异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成
*/
static all(promises) {
return new myPromise((resolve, reject) => {promises.forEach((item, index) => {myPromise.resolve(item).then(value => {count++;// 每个promise执行的结果存储在result中result[index] = value;// 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)count === promises.length && resolve(result);},reason => {reject(reason); })})
}
allSettled
static allSettled(promises) {
return new myPromise((resolve, reject) => {promises.forEach((item, index) => {myPromise.resolve(item).then(value => {count++;// 每个promise执行的结果存储在result中//A.记录所有reject/fulfilled,需要区分状态result[index] = {status: 'fulfilled',value}// 如果所有的 Promise 都已经处理完毕,就调用 resolve(result)count === promises.length && resolve(result);},reason => {//A.记录所有rejectcount++;result[index] = {status: 'rejected',reason}count === promises.length && resolve(result); })})
}
any
static any(promises){return new myPromise((resolve, reject) => {promises.forEach((item, index) => {myPromise.resolve(item).then(value => {//C.只要一个成功resolve(value);},reason => {//C.全rejectcount++;errors.push(reason);//AggregateError是 Error 的一个子类,用于把单一的错误集合在一起。count === promises.length && reject(new AggregateError(errors));})})
}
race
//race方法(返回最早执行完的promise结果,无论成功与否)
Promise.race = function(promises){return new myPromise((resolve, reject) => {// 如果传入的迭代promises是空的,则返回的 promise 将永远等待。if (promises.length > 0) {promises.forEach(item => {myPromise.resolve(item).then(resolve, reject);})}}})
手写实现 Promise 全部实例方法和静态方法,来看看 Promise.all、Promise.race 和 Promise.any 都是怎么实现的 - 掘金
从一道让我失眠的 Promise 面试题开始,深入分析 Promise 实现细节 - 掘金