想了解JS Promise具体怎么使用,请看【ES6基础知识】promise和await/async
为了更深入了解其原理,下面动手重写Promise源码
如有不对,欢迎指正。此文适合自己手动实践,能让自己功力大增。
重写MyPromise,基于它再重写then、catch、resolve、reject、finally
MyPromise
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
function MyPromise(executor) {
let self = this;
this.status = PENDING;
this.onFulfilled = [];//成功的回调
this.onRejected = []; //失败的回调
function resolve(value) {
if (self.status === PENDING) {
self.status = FULFILLED;
self.value = value;
//
self.onFulfilled.forEach(fn => fn()); //PENDING状态执行,如果前面多个then都是PENDING状态,就是数组,最后面一个then是FULFILLED状态,就是执行数组
}
}
function reject(reason) {
if (self.status === PENDING) {
self.status = REJECTED;
self.reason = reason;
self.onRejected.forEach(fn => fn());
}
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then
then支持链式调用,所以要用数组,then中根据状态来控制所执行的内容
MyPromise.prototype.then = function (onFulfilled, onRejected) {
// onFulfilled 和 onRejected必须是函数类型
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };
let self = this;
let promiseInstance = new MyPromise(
(resolve, reject) => {
// then中执行函数(onFulfilled, onRejected)是微任务
if (this.status === FULFILLED) {
// 不会变成其它状态
setTimeout(() => {
try {
// 必须在promise变成 fulfilled 时,调用 onFulfilled,参数是promise的value
// 在promise的状态不是 fulfilled 之前,不能调用
// onFulfilled 只能被调用一次
let x = onFulfilled(self.value);
resolvePromise(promiseInstance, x, resolve, reject);
} catch (error) {
reject(e);
}
})
} else if (self.status === REJECTED) {
// 不会变成其它状态
setTimeout(() => {
try {
let x = onRejected(self.reason);
resolvePromise(promiseInstance, x, resolve, reject);
} catch (e) {
reject(e);
}
});
} else if (self.status === PENDING) {
// 可以变成 fulfilled 或者是 rejected
// then方法可能被多次调用
// 如果promise变成了 fulfilled态,所有的onFulfilled回调都需要按照then的顺序执行
// 如果promise变成了 rejected态,所有的onRejected回调都需要按照then的顺序执行
self.onFulfilled.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(self.value);
resolvePromise(promiseInstance, x, resolve, reject);
} catch (e) {
// 如果 onFulfilled执行时抛出异常e,promiseInstance需要被reject
reject(e);
}
});
});
self.onRejected.push(() => {
setTimeout(() => {
try {
let x = onRejected(self.reason);
resolvePromise(promiseInstance, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
}
)
// then必须返回一个promise
return promiseInstance
}
function resolvePromise(promiseInstance, x, resolve, reject) {
let self = this;
if (promiseInstance === x) {
reject(new TypeError('Chaining cycle'));
}
// 如果 x 是一个 object 或者 是一个 function
if (x && typeof x === 'object' || typeof x === 'function') {
let used; //只能调用一次
//
try {
// 有.then
let then = x.then;
if (typeof then === 'function') {
// 如果 then 是一个函数,then.call(x, resolvePromiseFn, rejectPromiseFn)
then.call(x, (y) => {
// // 调用then函数的resolvePromiseFn
if (used) return;
used = true;
// then是链式,所以后面then执行的函数一样
resolvePromise(promiseInstance, y, resolve, reject);
}, (r) => {
// 调用then函数的rejectPromiseFn
if (used) return;
used = true;
reject(r);
});
} else {
// 不是函数,直接fulfill
if (used) return;
used = true;
resolve(x);
}
} catch (e) {
// x.then出错
if (used) return;
used = true;
reject(e);
}
} else {
// x 不是一个 object 或者 是一个 function
resolve(x);
}
}
catch
catch底层调用的是then,只不过resolved不执行
MyPromise.prototype.catch = function (onRejected) {
this.then(null, onRejected);
}
resolve
- MyPromise.resolve返回一个以给定值解析后的Promise 对象
- 如果 value 是个 thenable 对象,返回的promise会“跟随”这个thenable的对象,采用它的最终状态
- 如果传入的value本身就是promise对象,那么Promise.resolve将不做任何修改、原封不动地返回这个promise对象
- 其他情况,直接返回以该值为成功状态的promise对象。
MyPromise.resolve = function (param) {
if (param instanceof MyPromise) {
return param;
}
return new MyPromise((resolve, reject) => {
if (param && param.then && typeof param.then === 'function') {
setTimeout(() => {
param.then(resolve, reject);
});
} else {
resolve(param);
}
});
}
reject
参数会原封不动地作为reject的理由,变成后续方法的参数。
MyPromise.reject = function (reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
finally
finally底层调用的是then,FULFILLED和REJECTED都会执行,并且还能继续then,还会将值原封不动的传递给后面的then,所以返回的是一个Promise.resolve(返回Promise.resolve的原因是不管FULFILLED和REJECTED都会执行一个函数,并且还能把值往后传继续then)
MyPromise.prototype.finally = function (callback) {
return this.then((value) => {
return MyPromise.resolve(callback()).then(() => {
return value;
});
}, (err) => {
return MyPromise.resolve(callback()).then(() => {
throw err;
});
});
}
实例
const myPromise1 = (time, res) => new MyPromise(resolve => {
setTimeout(() => { resolve(res) }, time);
})
const myPromise2 = (time, res) => new MyPromise((resolve, reject) => {
throw new Error('async error!')
reject(new Error('test')); //有了throw,此处不会执行
})
myPromise1(600, 'myPromise1').then((res) => {
console.log(res) //myPromise1
}).catch((err) => {
console.log('final catch error:', err)
})
> myPromise1
myPromise2(600, 'myPromise2').then((res) => {
console.log(res)
}).catch((err) => {
console.log('final catch error:', err)
})
>
final catch error: Error: async error!
at .../Promise.js:407:9
使用原生Promise重写all、race、allSettled、any、finally
Promise类公共代码
class PromiseCls {
constructor() {
this.tasks = [];
}
addAsync(task){
this.tasks.push(task)
}
// 所有都变成resolved或者任何一个变成reject
all(){ ... }
// 只要有一个状态改变就结束
race(){ ... }
// 只有等到所有参数实例都返回结果,不管是fulfilled还是rejected,包装实例才会结束
allSettled(){ ... }
any(){ ... }
}
const timeout = (time,res) => new Promise(resolve => {
setTimeout(()=>{resolve(res)}, time);
})
const rejectAsync = (time,res) => new Promise((resolve, reject) => {
throw new Error('async error!')
reject(new Error('test')); //有了throw,此处不会执行
})
const notPromise = () => 'not Promise'
let promise = new PromiseCls();
all
all(){
let promiseArr = this.tasks;
return new Promise((resolve, reject)=>{
let resArr = [];
let index = 0;
for(let i=0,len=promiseArr.length; i<len; i++){
//如果不是Promise实例需要转化为Promise实例
Promise.resolve(promiseArr[i]).then(res => {
//promiseArr[i].then(res => {
index++;
// console.log(res) //not Promise, 3, 4, 2, 1
resArr[i] = res; //i得对应上
if( index === len){
resolve(resArr);
}
}).catch(e => {
console.log('one promise error:'+e)
reject(e)
});
}
}).catch((err)=> {
throw new Error('all function:' + err)
})
}
promise.addAsync(timeout(600, '1'));
promise.addAsync(timeout(500, '2'));
promise.addAsync(timeout(300, '3'));
promise.addAsync(timeout(400, '4'));
promise.addAsync(notPromise());
promise.all().then((res)=>{console.log(res)})
>
[ '1', '2', '3', '4', 'not Promise' ] 按照顺序输出
promise.addAsync(timeout(600, '1'));
promise.addAsync(timeout(500, '2'));
promise.addAsync(timeout(300, '3'));
promise.addAsync(rejectAsync(400, '4'));
promise.all().then((res)=>{console.log(res)}).catch((err)=> {
console.log('final catch error:',err)
})
>
one promise error:Error: async error!
final catch error: Error: all function:Error: async error!
at .../Promise.js:28:13
promise.addAsync(timeout(600, '1'));
promise.addAsync(timeout(500, '2'));
promise.addAsync(timeout(300, '3'));
promise.addAsync(rejectAsync(400, '4'));
promise.addAsync(rejectAsync(200, '4'));
promise.all().then((res)=>{console.log(res)}).catch((err)=> {
console.log('final catch error:',err)
})
>
one promise error:Error: async error!
one promise error:Error: async error!
final catch error: Error: all function:Error: async error!
at .../Promise.js:28:13
race
// 只要有一个状态改变就结束,如果不是Promise实例需要转化为Promise实例
race(){
let promiseArr = this.tasks;
return new Promise((resolve, reject)=>{
for(let i=0,len=promiseArr.length; i<len; i++){
Promise.resolve(promiseArr[i]).then(res => {
// promiseArr[i].then(res => {
resolve(res) //一经改变就不再可变
}).catch(e => {
console.log('one promise error:'+e)
reject(e)
});
}
}).catch((err)=> {
throw new Error('all function:' + err)
})
}
promise.addAsync(timeout(600, '1'));
promise.addAsync(timeout(500, '2'));
promise.addAsync(timeout(300, '3'));
promise.addAsync(timeout(400, '4'));
promise.race().then((res)=>{console.log(res)})
> 3
promise.addAsync(timeout(600, '1'));
promise.addAsync(timeout(500, '2'));
promise.addAsync(timeout(300, '3'));
promise.addAsync(rejectAsync(400, '4'));
promise.addAsync(rejectAsync(200, '4'));
promise.race().then((res)=>{console.log(res)}).catch((err)=> {
console.log('final catch error:',err)
})
>
one promise error:Error: async error!
one promise error:Error: async error!
final catch error: Error: all function:Error: async error!
at .../Promise.js:28:13
allSettled
// 不管是成功还是失败,都要全部执行完,所以需要考虑到finally
// 无论请求对错最终都会返回一个数组对象 到 .then 中,并切返回的数据中标识了错误跟正确数据的区别
allSettled(){
let promiseArr = this.tasks;
return new Promise((resolve) => {
let sttled = 0
let resArr = []
for(let i=0,len=promiseArr.length; i<len; i++){
Promise.resolve(promiseArr[i])
.then(res => {
resArr[i] = res;
// resArr[i] = {
// status: 'fulfilled',
// value: res
// }
})
.catch(err => {
resArr[i] = err;
// resArr[i] = {
// status: 'rejected',
// reason: err
// } 这么输出更清晰
})
.finally(() => { ++sttled === promiseArr.length && resolve(resArr) })
}
})
}
promise.addAsync(timeout(600, '1'));
promise.addAsync(timeout(500, '2'));
promise.addAsync(timeout(300, '3'));
promise.addAsync(notPromise());
promise.addAsync(rejectAsync());
promise.addAsync(rejectAsync());
promise.allSettled().then((res)=>{console.log(res)}).catch((err)=> {
console.log('final catch error:',err)
})
>
[
'1',
'2',
'3',
'not Promise',
Error: async error!
at .../Promise.js:107:9
Error: async error!
at .../Promise.js:107:9
]
any
子Promise中任意一个Promise完成时,就触发.then,成功触发.then中第一个方法,失败触发.then中第二个方法
// 只要一个成功就成功,失败要全部执行完
any(){
let promiseArr = this.tasks;
return new Promise((resolve, reject)=>{
let index = 0
let resArr = []
for(let i=0,len=promiseArr.length; i<len; i++){
Promise.resolve(promiseArr[i]).then(res => {
// promiseArr[i].then(res => {
resolve(res)
}).catch(e => {
index++
resArr.push(e);
if(index==promiseArr.length){
reject(resArr)
console.log('one promise error:'+e)
}
})
}
})
// .catch((err)=> {
// throw new Error('all function:' + err)
// })
}
promise.addAsync(timeout(600, '1'));
promise.addAsync(timeout(500, '2'));
promise.addAsync(timeout(300, '3'));
promise.addAsync(notPromise());
promise.addAsync(rejectAsync());
promise.addAsync(rejectAsync());
promise.any().then((res)=>{console.log(res)}).catch((err)=> {
console.log('final catch error:',err)
})
> not Promise
promise.addAsync(rejectAsync());
promise.addAsync(rejectAsync());
promise.any().then((res)=>{console.log(res)}).catch((err)=> {
console.log('final catch error:',err)
})
>
[
Error: async error!
at .../Promise.js:107:9
Error: async error!
at .../Promise.js:107:9
]
Promise.resolve(4) Promise A+创建两次微任务参考: 【V8源码补充篇】从一道让我失眠的 Promise 面试题开始,深入分析 Promise 实现细节 - 掘金 (juejin.cn)
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 因为执行了2次微任务,所以4在3后面
原生 Promise 创建两次微任务的位置:
- 第一次: 在发现 Promise.resolve(4) 的时候,创建 NewPromiseResolveThenableJob,并将其送入微任务队列
- 第二次: 在处理 Promise.resolve(4) 的时候,调用 then 方法时,内部创建了微任务来处理回调函数