1.概念:宏任務(macrotask )和微任務(microtask ) 表示異步任務的兩種分類。常見宏任務:I/O 、setTimeout、setInterval;微任務:Promise.then catch finally、process.nextTick
在掛起任務時,JS 引擎會將 所有任務 按照類別分到這兩個隊列中,
首先在 macrotask 的隊列(這個隊列也被叫做 task queue)中取出第一個任務,執行完畢后取出 microtask 隊列中的所有任務順序執行;
之后再取 macrotask 任務,周而復始,直至兩個隊列的任務都取完。
2.代碼
2.1 基本執行順序

// 主線程(外層宏) - 微 - 宏 // 1 1.1 - 2 - 3 setTimeout(() => { console.log('3') }, 0) console.log('1'); new Promise((resolve) => { console.log('1.1'); resolve() }).then(() => { console.log('2'); }).then(()=>{ console.log('2.1') })

setTimeout(_ => console.log(4)) new Promise(resolve => { resolve() console.log(1) }).then(_ => { console.log(3) }) console.log(2)

setTimeout(_ => console.log(4)) new Promise(resolve => { resolve() console.log(1) }).then(_ => { console.log(3) }) console.log(2)

setTimeout(() => { console.log("宏2"); }, 1000); setTimeout(() => { console.log("宏3"); }, 100); console.log("同步"); new Promise((resolve, reject) => { setTimeout(() => { console.log("宏1"); }, 0) console.log("立即"); resolve(); // reject() }) .then(() => { console.log("微0"); }) .then(() => { console.log("微0"); }) .catch(() => { console.log("err"); }) // 同步 立即 微0 微0 宏1 宏3 宏2
2.2 深度解析案例 :單組依次執行

console.log('1'); setTimeout(function() { console.log('3'); new Promise(function(resolve) { console.log('3.1'); resolve(); }).then(function() { console.log('4') }) }) new Promise(function(resolve) { console.log('1.1'); resolve(); }).then(function() { console.log('2') }) setTimeout(function() { console.log('5'); new Promise(function(resolve) { console.log('5.1'); resolve(); }).then(function() { console.log('6') }) })
2.3 promise ES5實現

function MyPromise(fn) { var value = null, callbacks = []; this.then = function (onFulfilled) { callbacks.push(onFulfilled); return this; }; function resolve(value) { setTimeout(function () { callbacks.forEach(function (callback) { callback(value); }); },0) } fn(resolve); } function test() { return new MyPromise(function(resolve) { console.log('1'); resolve(); }) } test().then(function(resolve) { console.log('2'); }).then(function(resolve) { console.log('3'); });

/** * Promise類實現原理 * 構造函數傳入一個function,有兩個參數,resolve:成功回調; reject:失敗回調 * state: 狀態存儲 [PENDING-進行中 RESOLVED-成功 REJECTED-失敗] * doneList: 成功處理函數列表 * failList: 失敗處理函數列表 * done: 注冊成功處理函數 * fail: 注冊失敗處理函數 * then: 同時注冊成功和失敗處理函數 * always: 一個處理函數注冊到成功和失敗 * resolve: 更新state為:RESOLVED,並且執行成功處理隊列 * reject: 更新state為:REJECTED,並且執行失敗處理隊列 **/ class PromiseNew { constructor(fn) { this.state = 'PENDING'; this.doneList = []; this.failList = []; fn(this.resolve.bind(this), this.reject.bind(this)); } // 注冊成功處理函數 done(handle) { if (typeof handle === 'function') { this.doneList.push(handle); } else { throw new Error('缺少回調函數'); } return this; } // 注冊失敗處理函數 fail(handle) { if (typeof handle === 'function') { this.failList.push(handle); } else { throw new Error('缺少回調函數'); } return this; } // 同時注冊成功和失敗處理函數 then(success, fail) { this.done(success || function () { }).fail(fail || function () { }); return this; } // 一個處理函數注冊到成功和失敗 always(handle) { this.done(handle || function () { }).fail(handle || function () { }); return this; } // 更新state為:RESOLVED,並且執行成功處理隊列 resolve() { this.state = 'RESOLVED'; let args = Array.prototype.slice.call(arguments); setTimeout(function () { this.doneList.forEach((item, key, arr) => { item.apply(null, args); arr.shift(); }); }.bind(this), 200); } // 更新state為:REJECTED,並且執行失敗處理隊列 reject() { this.state = 'REJECTED'; let args = Array.prototype.slice.call(arguments); setTimeout(function () { this.failList.forEach((item, key, arr) => { item.apply(null, args); arr.shift(); }); }.bind(this), 200); } } // 下面一波騷操作 new PromiseNew((resolve, reject) => { resolve('hello world'); // reject('you are err'); }).done((res) => { console.log(res); }).fail((res) => { console.log(res); })
2.4 promise 常見用法
鏈式調用:
Promise的精髓是“狀態”,用維護狀態、傳遞狀態的方式來使得回調函數能夠及時調用,它比傳遞callback函數要簡單、靈活的多
超時:
用race給某個異步請求設置超時時間,並且在超時后執行相應的操作
3.相關文章