實(shí)現(xiàn) JS promise

https://promisesaplus.com/
需求包括:

  1. 同一個(gè)promise允許被多次then/catch
  2. then/catch函數(shù): then(onFulfilled, onRejected), catch(onRjecte)
    • then/catch 返回一個(gè)新的promise,因此允許鏈?zhǔn)秸{(diào)用
    • onFulfilled/onReject為null時(shí), 繼續(xù)將當(dāng)前result/error往之后的chain傳
    • 每個(gè)onFulfilled/onReject最多被執(zhí)行一次
    • onFulfilled/onReject執(zhí)行過(guò)程中拋出異常時(shí),立即往之后的chain拋異常
    • 鏈尾的異常不應(yīng)該被之前的promise catch到
    • catch之后被恢復(fù): 執(zhí)行onRjected的返回值作為result

實(shí)現(xiàn)要點(diǎn):

  1. 如何讓同一個(gè)promise多次then/catch: 每個(gè)promise維護(hù)一個(gè)defer callbacks隊(duì)列,每次then時(shí)將callback加入隊(duì)列就好了
  2. 如何返回新的promise: 將傳給then的onFulfilled/onReject改造成v => next_resolve(onFulfilled(v)), e => next_resolve(onRjected(e))
  3. 注意try/catch細(xì)節(jié),和處理下onFulfilled/onReject可能返回promise的情況
let isThenable = x => !!(x!==undefined && x.then);
let runThenable = (func, arg) => isThenable(arg) ? arg.then(func) : func(arg);

class MyPromise{
 constructor(f){
   this.succ_que = [];
   this.fail_que = [];
   this.done = false;

   this.resolve = result => {
     if(this.done) return;
     this.result = result;
     this.done = true;
     setImmediate(() => {          // setImmediate to prevent children from being caught by parent
       this.succ_que.forEach(cb => cb(result));
     });
   };

   this.reject = error => {
     if(this.done) return;
     this.error = error;
     this.done = true;
     setImmediate(() => {
       this.fail_que.forEach(cb => cb(error));
     });
   };

   this.then = (succ_cb, fail_cb) => new MyPromise((next_resolve, next_reject) => {
     let handle_result = v => {
       try{
         runThenable(next_resolve, succ_cb ? succ_cb(v) : v);    // runThenable to allow succ_cb/fail_cb return a promise
       } catch (e) {
         next_reject(e)
       }
     };
     let handle_error = e => {
       try{
         if(fail_cb)
           runThenable(next_resolve, fail_cb(e));    // resume after caught by fail_cb
         else
           next_reject(e);
       }catch (e) {
         next_reject(e)
       }
     };

     if(this.done){
       this.error ? handle_error(this.error) : handle_result(this.result)
     }else{
       this.succ_que.push(handle_result);
       this.fail_que.push(handle_error);
     }
   });

   this.catch = fail_cb => this.then(null, fail_cb);

   try{
     f(this.resolve, this.reject);
   }catch (e) {
     this.reject(e);
   }
 }
}

MyPromise.resolve = x => new MyPromise(r => r(x));
MyPromise.Race = (...promises) => {
 let done = 0;
 return new MyPromise(r => {
   promises.forEach(p => p.then(v =>{ if(!done){done++; r(v);} }));
 })
};
MyPromise.All = (...promises)=>{
 let count = promises.length;
 let values = [];

 return new MyPromise((r, f) => {
   promises.forEach((p, i) =>
     p.then(v => {
       values[i] = v;
       count --;
       if(count === 0) r(values);
     }, f)
   )
 });
};
// tests:
// then/catch on the same promise:
let defer = new MyPromise(r => setImmediate(()=>r(100)));
[1,2,3].forEach(plus => defer.then(v => console.log(v+plus)));    // 101, 102, 103

let defer_error = new MyPromise((_, rej) => setImmediate(()=>rej(new Error("defer error"))));
[1,2,3].forEach(i => defer_error.catch(e => console.log(i, e.message)));

// chained then/catch:
let p = MyPromise.resolve(1);
p.then(v=> v+1)
  .catch(e => console.log(`won't happen error: ${e}`))
  .then(v => {console.log(`continued: ${v}`); throw new Error("throw");})
  .then(v => {console.log("won't happen then");})
  .catch(e => {console.log(`catched: ${e}`); return 100;})
  .then(v => {console.log(`continue after catch: ${v}`); return v;})
  .then(v => new MyPromise(r=> setTimeout(() => r(v+500), 3000)))
  .then(v => console.log(`last: ${v}`))
;
console.log("===========");

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容