JavaScript | 2020-09-28 20:27:53 1799次 4次
上篇通过 promise A+ 规范进行了代码举例,本次进行一个 promise 模拟实现,具体实现代码放在这里。
测试库:
npm i -g promises-aplus-tests promises-aplus-tests Promise.js
一、Promise 模拟实现
1、定义
// promise 三个状态 const PENDING = "pending"; const FULFILLED = "fulfilled"; const REJECTED = "rejected"; function Promise(excutor) { let that = this; // 缓存当前promise实例对象 that.status = PENDING; // 初始状态 that.value = undefined; // fulfilled状态时 返回的信息 that.reason = undefined; // rejected状态时 拒绝的原因 that.onFulfilledCallbacks = []; // 存储fulfilled状态对应的onFulfilled函数 that.onRejectedCallbacks = []; // 存储rejected状态对应的onRejected函数 function resolve(value) { // value成功态时接收的终值 // resolve的值是一个promise,2.3.2 if(value instanceof Promises) { return value.then(resolve, reject); } // 模拟微任务 setTimeout(() => { // 调用resolve 回调对应onFulfilled函数 if (that.status === PENDING) { // 只能由pedning状态 => fulfilled状态 (避免调用多次resolve reject) that.status = FULFILLED; that.value = value; that.onFulfilledCallbacks.forEach(cb => cb(that.value)); } }); } function reject(reason) { // reason失败态时接收的拒因 setTimeout(() => { // 调用reject 回调对应onRejected函数 if (that.status === PENDING) { // 只能由pedning状态 => rejected状态 (避免调用多次resolve reject) that.status = REJECTED; that.reason = reason; that.onRejectedCallbacks.forEach(cb => cb(that.reason)); } }); } // 捕获在excutor执行器中抛出的异常 // new Promise((resolve, reject) => { // throw new Error('error in excutor') // }) try { excutor(resolve, reject); } catch (e) { reject(e); } }
2、then
Promises.prototype.then = function(onFulfilled, onRejected) { const that = this; let newPromise; // 2.2.7.3 | 2.2.7.4 透传 onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value; onRejected = typeof onRejected === "function" ? onRejected : reason => { throw reason; }; if (that.status === FULFILLED) { // 成功态 return newPromise = new Promise((resolve, reject) => { setTimeout(() => { try{ let x = onFulfilled(that.value); // 新的promise resolve 上一个onFulfilled的返回值 resolvePromise(newPromise, x, resolve, reject); } catch(e) { // 捕获前面onFulfilled中抛出的异常 then(onFulfilled, onRejected); reject(e); } }); }) } if (that.status === REJECTED) { // 失败态 return newPromise = new Promise((resolve, reject) => { setTimeout(() => { try { // 2.2.7.1 let x = onRejected(that.reason); resolvePromise(newPromise, x, resolve, reject); } catch(e) { reject(e); } }); }); } if (that.status === PENDING) { // 等待态 // onFulfilled/onRejected 收集 return newPromise = new Promise((resolve, reject) => { that.onFulfilledCallbacks.push((value) => { try { // 2.2.7.2 let x = onFulfilled(value); resolvePromise(newPromise, x, resolve, reject); } catch(e) { reject(e); } }); that.onRejectedCallbacks.push((reason) => { try { let x = onRejected(reason); resolvePromise(newPromise, x, resolve, reject); } catch(e) { reject(e); } }); }); } };
3、解析过程
function resolvePromise(promise2, x, resolve, reject) { // 2.3.1 if (promise2 === x) { // 如果从onFulfilled中返回的x 就是promise2 就会导致循环引用报错 return reject(new TypeError('Chaining cycle detected for promise #<Promise>')); } let called = false; // 避免多次调用 2.2.2.3 // 如果x是一个promise对象 2.3.2 if (x instanceof Promises) { // 获得它的终值 继续resolve if (x.status === PENDING) { // 如果为等待态需等待直至 x 被执行或拒绝 并解析y值 x.then(y => { resolvePromise(promise2, y, resolve, reject); }, reason => { reject(reason); }); } else { // 如果 x 已经处于执行态/拒绝态(值已经被解析为普通值),用相同的值执行传递下去 promise x.then(resolve, reject); } // 如果 x 为对象或者函数 2.3.3 } else if (x != null && ((typeof x === 'object') || (typeof x === 'function'))) { try { // 是否是thenable对象(具有then方法的对象/函数) let then = x.then; if (typeof then === 'function') { then.call(x, y => { if(called) return; called = true; resolvePromise(promise2, y, resolve, reject); }, reason => { if(called) return; called = true; reject(reason); }) } else { // 说明是一个普通对象/函数 return {then:5} resolve(x); } } catch(e) { if(called) return; called = true; reject(e); } } else { // 2.3.4 resolve(x); } }
4、race
race 是一个静态方法,仅执行最快的那个,利用【2.2.2.3】特性
Promises.race = function(promises) { return new Promises((resolve, reject) => { promises.forEach((promise, index) => { // 最快的执行完之后,后面的 resolve | reject 不生效 promise.then(resolve, reject); }); }); }
5、all
Promises.all = function(list) { return new Promise((resolve, reject) => { let resValues = []; let counts = 0; list.forEach((p, i) => { p.then(res => { counts++; resValues[i] = res; if (counts === list.length) { resolve(resValues) } }, err => { reject(err) }) }) }) }
但是 all 此时的方法有问题,比如其中一个失败,则成功的结果也得不到,都进到了 catch 里面,需要进行优化下:
function handlePromise(promiseList) { return promiseList.map(promise => promise.then((res) => ({ status: 'ok', res }), (err) => ({ status: 'not ok', err })) ) } Promise.allSettled = function (promiseList) { return Promise.all(handlePromise(promiseList)) } Promise.allSettled ([ Promise.reject(1), Promise.resolve(2), Promise.resolve(3) ]).then(res => console.log(res), err => console.log(err))
6、finally
示例: let promise = new Promise((resolve, reject) => { reject('this is error') }) promise.then((value) => { console.log('fulfill', value) }).finally(res => { // undefined end console.log(res, 'end') }).catch(err=>{ // this is error reject console.log(err, 'reject') })
实现: Promises.prototype.finally = function (callback) { let P = this.constructor; return this.then( //xxx.then(() => value) -- finally后可以继续 .then 等 value => P.resolve(callback()).then(() => value), // reject 抛出错误 继续 catch 可以捕获 reason => P.resolve(callback()).then(() => { throw reason }) ); };
7、其他
// 直接 reject Promises.prototype.catch = function(onRejected) { return this.then(null, onRejected); } //静态方法 resolve Promises.resolve = function (value) { return new Promises(resolve => { resolve(value); }); } // 静态方法 reject Promises.reject = function (reason) { return new Promises((resolve, reject) => { reject(reason); }); }
二、可取消的Promise
function getWithCancel(promise, token) { let handle = {} Promise.race([promise, new Promise((_, reject) => { handle.cancel = function() { reject(new Error('cancel')) } })]).catch((e) => console.log(e)) return handle; }; var promise = fetch(xxxxx) getWithCancel(promise).cancel()
三、async/await原理
async/await 是 promise 和 Generator 语法糖。参考
async function fn(args) { // ... } // 等同于 function fn(args) { return spawn(function* () { // ... }); }
function spawn(genF) { return new Promise(function(resolve, reject) { const gen = genF(); function step(nextF) { let next; try { next = nextF(); } catch(e) { return reject(e); } if(next.done) { return resolve(next.value); } Promise.resolve(next.value).then(function(v) { step(function() { return gen.next(v); }); }, function(e) { step(function() { return gen.throw(e); }); }); } step(function() { return gen.next(undefined); }); }); }
4人赞