author: 陳家賓 email: 617822642@qq.com date: 2018/2/23
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 的內容就到此爲止了,後來看到了阮老師的一篇博客,裏面說異步分兩種,what?!!java
異步任務能夠分紅兩種。node
- 追加在本輪循環的異步任務
- 追加在次輪循環的異步任務
Node 規定,
process.nextTick
和Promise
的回調函數,追加在本輪循環,即同步任務一旦執行完成,就開始執行它們。而setTimeout
、setInterval
、setImmediate
的回調函數,追加在次輪循環。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
單詞 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