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.相关文章