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