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给某个异步请求设置超时时间,并且在超时后执行相应的操作
本文深入探讨了JavaScript中宏任务和微任务的概念,通过具体示例解释了它们的执行顺序,展示了Promise如何作为微任务在宏任务间插入执行,以及Promise的ES5实现和常见用法。
3657

被折叠的 条评论
为什么被折叠?



