<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                - resolve的是一個promise - then中return了一個promise - 防止循環引用 - 延遲設計 - 初衷猜想 - 關于異常捕獲 - 值的穿透 [TOC] ## pre-notify previously : - [Promise深度學習---我のPromise/A+實現](https://juejin.im/post/5a59e78ff265da3e3e33ba6e) - [異步發展簡明指北](https://juejin.im/post/5a6212386fb9a01ca5608de3) 最近發現掘金上又多了很多promise相關的文章,于是乎把一年前寫的東東拿出來看了看,又理了理,于是乎就有了這么一篇文。 > 時間獲取并不是平白的流過,TA能讓有些事逐漸變得清晰,只要沒有徹底放手 ## resolve的是一個promise promise允許resolve里可以是一個promise。 比如說 假如我們有一個promise1,這個promise1`resolve`的也是一個promise,我們姑且稱之為promise2,那么這個promise2的結果將作為我們promise1的結果(狀態和值)。 ``` let p = new Promise(function(resolve,reject){ resolve(new Promise(function(resolve,reject){ resolve('a'); })) }); >>> p.value <<< a ``` 并且這個promise可以無限的在resolve中嵌套下去。 而我們只需要記住我們最終拿到的promise的結果是**最里層的promise的結果**即可。 --- 實現 ``` function resolve(value){ // value可能是一個promise if(value!==null&&(typeof value==='object'||typeof value==='function')){ return value.then(resolve,reject); } ... } ``` 思維模型圖大概長這樣 ![](https://box.kancloud.cn/8bbfd238c1d3487194c49f5afba53856_698x84.png) 就像一個個鉤子,綁定和定義的順序是從右往左,執行時是從左往右 ## then中return了一個promise 正常情況下如果then中return的是一個普通值,那么會走下一個then中的成功回調,并且這個return的值會作為回調的參數傳入。 但如果是一個promise,則會根據這個promise的狀態來決定走下一個then中的哪個回調,并且以這個promise的值作為回調的參數傳入。 ``` p.then(function(data){ return new Promise(function(resolve,reject){ resolve(100); }) }).then(function(data){ console.log(data); }) <<< 100 ``` 其次這個返回的promise里也可像上面的說過的一樣在這個promise里的resolve里繼續嵌套promise ``` p.then(function(data){ return new Promise(function(resolve,reject){ resolve(new Promise(resolve,reject){ resolve(200); }); }) }).then(function(data){ console.log(data); }) <<< 200 ``` --- 實現: 這大概是Promise實現最難的一部分,主要是通過一個`resolvePromise`的方法來支持我們上述的功能,先上完整代碼 ``` function resolvePromise(p2,x,resolve,reject){ // 注意:有可能解析的是一個第三方promise if(p2 === x){ //防止循環引用 return reject(new TypeError('Error:循環引用')); //讓promise2失敗 } let called; // 防止第三方的promise出現可能成功和失敗的回調都調用的情況 if(x!==null||(typeof x === 'object')||typeof x === 'function'){ // 進來了只能說明可能是promise try{ let then = x.then; if(typeof then === 'function'){ then.call(x,function(y){ if(called) return; //這里可能交由的是第三方promise來處理,故可能被調用兩次 called = true; // p.then(function(){return new Promise(){resolve(new Promise...)}}) return中的promise的resolve又是一個promise,即y又可能是一個promise resolvePromise(p2,y,resolve,reject); },function(err){ if(called) return; called = true; reject(err); }); }else{ resolve(x); //可能只是組鍵值對,像這樣{then:1} } }catch(e){ // Object.define({},'then',{value:function(){throw Error()}}) if(called) return; // 防止第三方promise失敗時 兩個回調都執行 導致觸發兩次reject注冊的回調 called = true; reject(e); } }else{ //說明是個普通值 讓p2成功 resolve(x); } } ``` 其中尤其要重視的是這一部分 ``` if(typeof then === 'function'){ then.call(x,function(y){ resolvePromise(p2,y,resolve,reject); },function(err){ if(called) return; called = true; reject(err); }); } ``` 這里,此時then中成功回調的這個y參數即有可能是我們所說的resolve里嵌套promise的情況, 故我們需要將這個y傳入`resolvePromise`方法再次進行解析,這樣不斷遞歸,直到這個y變成一個普通值,我們以這個普通值來resolve我們then中返回的promise。 ## 防止循環引用 如果我們在一個`then`中return了一個promise,且這個promise還恰巧是then后返回的promise本身,那么這個then返回的promise永遠不可能會轉換狀態。So為了防止出現這種情況我們會直接reject it。 ``` 如果then中返回的promise是它本身就reject it let p = new Promise(function(resolve,reject){ resolve(); }); var p2 = p.then(function(){ return p2; //<---看這里!! }); p2.then(function(){ },function(e){ console.log(e); //會走這里 }); ``` --- 實現: 主要是`resolvePromise`方法中的這么一句 ``` if(p2 === x){ //防止循環引用 return reject(new TypeError('Error:循環引用')); //讓promise2失敗 } ``` ## 延遲設計 在promise的設計中,即使promise里沒有異步resolve,通過promise`then`注冊的回調也只會在標準的同步代碼執行完成后才會執行 ``` let p = new Promise(function(resolve,reject){ resolve(222); }); p.then(function(data){ console.log(data); }) console.log(111); <<< 111 222 ``` 我們可以在代碼中這樣實現 ``` ... promise2 = new Promise(function(resolve,reject){ // 因為返回值可能是普通值也可能是一個promise,其次也可能是別人的promise,故我們將它命名為x, setTimeout(function(){ try{ let x = onFulfilled(self.value); resolvePromise(promise2,x,resolve,reject); }catch(e) { reject(e); } }); }); ... ``` 即讓then回調執行之前套上一層`setTimeout`,讓它在下一輪執行。 (但實際上原生的promise實現是將其作為微任務而不是宏任務執行的)。 ### 初衷猜想 這么設計很重要的一個原因在我看來是因為執行then回調時,我們會調用`resolvePromise`這個方法,而調用這個方法時我們需要將then新返回的promise傳入,但我們能在一個new的過程中拿到自己嗎? 像這樣 ``` let a = new A(){ console.log(a); } ``` 這樣顯然拿到的是`undefined`。 So,為了拿到這個新返回的promise,故我們在外面套了一層`setTimeout`這樣的東東。 ## 關于異常捕獲 一個then,只要它有return,那么下一個then就會走成功的回調,即使這個return的是一個狀態為失敗態的promise。 ``` p.then(function(data){ return new Promise(function(resolve,reject){ reject('失敗'); }) }) .then(function(data){ console.log('會走成功'); },function(err){ }) <<< 會走這里 ``` 只有一種情況下一個then會走失敗的回調,那就是此次的回調執行是拋出了異常, ``` p.then(function(data){ throw Error('出現錯誤!') }) .then(function(data){ console.log('會走成功'); },function(err){ console.log(err) }) <<< 出現錯誤! ``` --- 實現: 我們在兩個地方使用過try catch 一個是`executor`執行的時候 ``` try{ // 正因為executor執行是同步的,故我們能使用try catch executor(resolve,reject); }catch(e){ reject(e); } ``` 一個是我們`then`所注冊的回調執行的時候 ``` ... promise2 = new Promise(function(resolve,reject){ setTimeout(function(){ try{ let x = onFulfilled(self.value); resolvePromise(promise2,x,resolve,reject); }catch(e) { reject(e); } }); }); ... ``` ## 值的穿透 promise允許我們使用空then(即使這樣做并沒有什么意義),而這些省略了回調的then原本改接收的參數會被向下傳遞直到遇到一個不是空的then。 ``` var p = new Promise(function(resolve,reject){ resolve(100) }); p.then().then().then(function(data){ console.log(data); },function(err){ console.log(err) }); <<< 100 //也允許異常向下傳遞 ``` --- 實現: ``` Promise.prototype.then = function(onFulfilled,onRejected){ // 成功和失敗默認不傳,則讓他們穿透直到有傳值的then onFulfilled = typeof(onFulfilled)==='function'?onFulfilled:function(value){ return value; }; onRejected = typeof(onRejected)==='function'?onRejected:function(err){ throw err; }; ... ``` ## 源碼 倉庫:[點我獲取](https://github.com/fancierpj0/iPromise) --- > 時間或許并不是平白的流過,只要一直在嘗試著,TA似乎能讓有些事逐漸變得清晰 --- end ---
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看