Promise
- 其实就是一个类,外部保留着回调队列,通过裸露resolve和reject办法触发对应回调
- 外部有三种状态值,pending,fulfiled,failed
- Promise是微工作,与settimout等宏工作有差异,执行程序时是,先主线程,而后微工作,而后宏工作
- 有以下几种办法:then, catch, all, race, resolve, reject
- 一旦实例了一个Promise,其就肯定会执行,无奈进行
- Promise中,因为报错也会触发reject,所以不会中断程序
- catch其实是then的语法糖,相当于then(null,rej),即胜利回调传了空
- 如果then中,没有传入回调,则promise的resolve或reject值会传递到下一个then或catch中,如下:
const p = new Promise((res) => res(2));p.then(null).then((data) => console.log(data)); // 2p.then(() => {}).then((data) => console.log(data)); // undefinedp.catch((data) => {console.log('catch', data)}).then((data) => console.log('then', data)); // then, 2
实现
function myPromise(func) { this.status = 'pending'; // 状态 this.value = undefined; // 值 this.resolveList = []; // 胜利回调 this.rejectList = []; // 失败回调}
- 外部resolve和reject办法
- 同时执行传入的func
function myPromise(func) { this.status = 'pending'; // 状态 this.value = undefined; // 值 this.resolveList = []; // 胜利回调 this.rejectList = []; // 失败回调 const resolve = (data) => { queueMicrotask(() => { // 新建微工作 if (this.status === 'pending') { this.status = 'fulfiled'; this.value = data; this.resolveList.forEach((resFunc) => resFunc(data)); this.resolveList.length = 0; } }); }; const reject = (data) => { queueMicrotask(() => { // 新建微工作 if (this.status === 'pending') { this.status = 'failed'; this.value = data; this.rejectList.forEach((resFunc) => resFunc(data)); this.rejectList.length = 0; } }); }; if (typeof func === 'function') { try { func(resolve, reject); // promise传入的func是马上执行的,但回调resolve和reject是异步微工作 } catch(err) { reject(err); } }}
- then办法, 定义在原型链上, 返回一个promise
- 分三种状态解决,pending时仅把回调传入同时promise化,fulfilled或failed时间接执行,并promise返回
- 这里能够看出下面形容的,如果resCb或rejCb传入为空,会将promise的value传递给返回的promise
- 并且如果cb返回的是promise,会以那个promise的res或rej触发下层的res或rej,同时cb中的data值是内层promise的value
myPromise.prototype.then = function (resCb, rejCb) { if (this.status === 'pending') { return new myPromise((res, rej) => { this.resolveList.push(function () { // 如果没有定义回调,将值传递给下一个 try { const ret = typeof resCb === 'function' ? resCb(this.value) : this.value; if (ret instanceof myPromise) { ret.then(res, rej); } else { res(ret); } } catch (err) { rej(err); } }); this.rejectList.push(function () { // 如果没有定义回调,将值传递给下一个 try { const ret = typeof rejCb === 'function' ? rejCb(this.value) : this.value; if (ret instanceof myPromise) { ret.then(res, rej); } else { rej(ret); } } catch (err) { rej(err); } }); }); } else if (this.status === 'fulfiled) { return new myPromise((res, rej) => { try { const ret = typeof resCb === 'function' ? resCb(this.value) : this.value; if (ret instanceof myPromise) { ret.then(res, rej); } else { res(ret); } } catch (err) { rej(err) } }); } else if (this.status === 'failed') { return new myPromise((res, rej) => { try { const ret = typeof rejCb === 'function' ? rejCb(this.value) : this.value; if (ret instanceof myPromise) { ret.then(res, rej); } else { rej(ret); } } catch (err) { rej(err) } }); }};
myPromise.prototype.catch = (rej) => myPromise.prototype.then(null, rej);
- all办法,传入一个数组,输入一个promise,全副resolve时,输入promise状态变为fulfiled,触发resolve
- 当任何一个传入的promise失败时,输入promise状态变failed,触发reject,但并不会终止其余promise继续执行,只是其余promise的执行曾经不会影响promise.all返回promise的状态了
myPromise.prototype.all = (iterable) => { const len = iterable.length; const result = []; return new myPromise((resolve, reject) => { let index = 0; iterable.forEach((item) => { item.then((data) => { result.push(data); index++; if (index === len) resolve(result); }, (err) => { reject(err); }); }); });}
- race办法,返回promise数组中第一个执行结束的状态,无论是fulfiled还是failed,但不影响数组中其余promise继续执行
myPromise.prototype.race = (iterable) => { let done = false; return new myPromise((resolve, reject) => { iterable.forEach((item) => { item.then((data) => { if (!done) { done = true; resolve(data); } }, (err) => { if (!done) { done = true; reject(err); } }); }); });}
- 其中下面的done标记能够去掉,因为promise中,resolve两次,只会在首次执行then函数,具体起因是,第一次resolve时,执行resolveList中的回调函数,执行结束后会把其清零,即如果没有在执行结束后再注册新的then办法,第二次resolve不会触发回调
- 另外即便在第二次reslove后新注册了一个then,其获取的值也是第一次resolve的值,而不是第二次resolve的值,这是因为更新promise内的value只会产生在promise状态从pending变为fulfiled或failed的时候,而第一次resolve曾经让状态变了,不会再触发value的更新,例子如下:
const p1 = new Promise((res) => { setTimeout(() => { console.log('res(1)'); res(1)}, 1000); setTimeout(() => { console.log('res(2)'); res(2)}, 3000);});p1.then((data) => console.log(data));setTimeout(() => { console.log('then again'); p1.then((data) => console.log(data));}, 5000);/* 输入 res(1) -> 1 -> res(2) -> then again -> 1最初输入1而不是2*/
myPromise.prototype.race = (iterable) => { return new myPromise((resolve, reject) => { iterable.forEach((item) => { item.then(resolve, reject); }); });}
- reslove和reject办法,其实就是裸露外部定义的reslove和reject
myPromise.prototype.reslove = (data) => { return new myPromise((resolve, reject) => { resolve(data); });};myPromise.prototype.reject = (data) => { return new myPromise((resolve, reject) => { reject(data); });};