Promise 基本原理 & 異步

author: 陳家賓
email: 617822642@qq.com
date: 2018/2/23

Promise 基本實現

var PENDING = 0;
var FULFILLED = 1;
var REJECTED = 2;

function Promise(fn) {
    var state = PENDING;
    var value = null;
    var handlers = [];

    doResolve(fn, resolve, reject)

    function fulfill(result) {}
    // state=fulfilled, value=result

    function reject(error) {}
    // state=rejected, value=error

    function resolve(result) {}
    // if then in result(result 是個 promise), 執行 doResolve
    // else 執行 fulfill
    
    function doResolve(fn, onFulfilled, onRejected) {}
    // 給 fn 傳入 resolve 和 reject 函數
    // resolve 函數,執行 onFulfilled
    // reject 函數,執行 onRejected
    
    function handle(handler) {}
    // if PENDING, push handler
    // if FULFILLED, 執行 handler 中的 onFulfilled 函數
    // if REJECTED, 執行 handler 中的 onRejected 函數
    
    this.done = function (onFulfilled, onRejected) {}
    // 異步(setTimeout 0)執行 handler({onFulfilled, onRejected})
    
    this.then = function (onFulfilled, onRejected) {
        var self = this
        return new Promise((resolve,reject)=>{
            return self.done(result=>{
                if onFulfilled
                    return resolve(onFulfilled(result))
                else 
                    return resolve(result)
            }, err=>{
                if onRejected
                    return resolve(onRejected(err))
                else
                    return reject(err)
            })
        })
    }
}

基本語法javascript

new Promsie((resolve, reject) => {
    // function1()
    resolve()
}).then(() => {
    // function2()
})

這裏 function1 同步執行,function2 異步執行html

Promise 本輪循環 & 次輪循環

原本覺得 Promise 的內容就到此爲止了,後來看到了阮老師的一篇博客,裏面說異步分兩種,what?!!java

異步任務能夠分紅兩種。node

  • 追加在本輪循環的異步任務
  • 追加在次輪循環的異步任務

Node 規定,process.nextTickPromise的回調函數,追加在本輪循環,即同步任務一旦執行完成,就開始執行它們。而setTimeoutsetIntervalsetImmediate的回調函數,追加在次輪循環。git

異步分兩種已經讓我大開眼界,但在個人知識世界裏,Promise 不是用 setTimeout 來實現異步的嗎,爲何 Promise 和 setTimeout 還分屬於不一樣的異步類型裏呢?es6

OK,立刻找一下 Promise 的 polyfill 原碼github

if (isNode) {
  scheduleFlush = useNextTick();
} else if (BrowserMutationObserver) { // BrowserMutationObserver = window.MutationObserver
  scheduleFlush = useMutationObserver();
} else if (isWorker) { // typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined'
  scheduleFlush = useMessageChannel();
} else if (browserWindow === undefined && typeof require === 'function') { // browserWindow = typeof window !== 'undefined' ? window : undefined
  scheduleFlush = attemptVertx();
} else {
  scheduleFlush = useSetTimeout();
}

原來 Promise 的異步不單單只是 setTimeout,這裏會根據不一樣環境來採用不一樣的實現方式,瀏覽器中主要用了 MutationObserver 和 setTimeoutpromise

咱們先來看一下 MutationObserver 的兼容性(下圖參考 https://developer.mozilla.org...瀏覽器

由上圖可知,使用 polyfill,從以上版本開始,Promise 是由 MutationObserver 實現的本輪循環的異步任務,低於以上版本的,則是由 setTimeout 實現的次輪循環的異步任務(本輪循環在次輪循環以前執行)。其帶來的具體差異以下:異步

// ie11
setTimeout(function () {console.log(1)});
Promise.resolve().then(function () {
  console.log(2);
});
// 輸出結果爲 2 1

// ie10
setTimeout(function () {console.log(1)});
Promise.resolve().then(function () {
  console.log(2);
});
// 輸出結果爲 1 2

其餘

shim VS polyfill

  • shim,給瀏覽器帶來新 API 的庫,如 jQuery
  • polyfill 則是針對瀏覽器的一種補丁,一種補充,使其行爲與其餘瀏覽器保持一致,如 promise-polyfill

單詞 polyfill 的由來:

Polyfilla is a UK product known as Spackling Paste in the US. With that in mind: think of the browsers as a wall with cracks in it. These [polyfills] help smooth out the cracks and give us a nice smooth wall of browsers to work with.——Remy Sharp

參考資料

  1. 《Node 定時器詳解》,阮一峯,2018年2月23日,http://www.ruanyifeng.com/blo...
  2. What is the difference between a shim and a polyfill? ,stack overflow,closed at Jul 30 '15,https://stackoverflow.com/que...
  3. 《Speaking JavaScript》,Axel Rauschmayer,March 2014,http://speakingjs.com/es5/ch3...
相關文章
相關標籤/搜索