宏任务与微任务
个人学习笔记↓
js处理程序分为同步与异步,其中宏任务与微任务是异步的两种分类
当js挂起任务时:
1)所有同步任务都在主线程上执行,形成一个执行栈
2)主线程之外,还存在一个"任务队列"。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件
3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列",看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行
4)主线程不断重复上面的第三步
console.log(1);
setTimeout(() => {
console.log(2);
});
console.log(3);
// 输出结果是 顺序 1,3,2 可知在未设置延迟时间时setTimeout仍是异步
其中,setTimeout的延时是当延迟时间到达时 才将延时函数中的内容安排到队列中,因此只要有setTimeout出现,其内的任务执行就已经不在该次任务队列中
console.log(1);
setTimeout(() => {
console.log(2);
},10);
setTimeout(() => {
console.log(3);
});
console.log(4);
// 输出结果是 顺序 1,4,3,2 可知异步结果跟它任务完成时间有关 谁先完成谁先打印。
// 同步不可 存在阻塞的问题
作为典型的异步事件 ajax请求中:
function ajax(url,cb,data){
data = data || {};
var str = "";
for (var i in data ){
str = str + i +"="+data[i]+"&";
}
str = str.slice(0, str.length - 1);
url = url +"?"+str + "_cfq="+Date.now();
var xhr = new XMLHttpRequest();
xhr.open("get",url,true);
xhr.onreadystatechange = function(){
if(xhr.readyState===4 && xhr.status===200){
cb(xhr.responseText)
}
}
xhr.send(null)
}
在ajax中XMLHttpRequset
对象发起请求,设置回调函数用来处理XHR的readystatechange
事件,然后执行XHR的send方法,在XHR运行中,只有xhr.readyState && xhr.status
改变时readystatechange
事件就会触发,因此只有在XHR从远端服务器接收响应结束时回调函数才会触发执行。
当然此时处理回调函数也是在主线任务结束时,从任务队列中取出回调,进入主线程执行。
重点↓↓↓↓↓↓↓
置于异步中的宏任务与微任务,则是在异步队列中,对异步的分类:
宏任务:script,setTimeout,setInterval
微任务:Promise,process.nextTick(nodejs)
当一次宏任务执行完毕,会执行挂载中的所有微任务,当微任务执行结束,再一次执行第二个宏任务。
取自:掘金←←大佬
大佬的示例
setTimeout(function() {
console.log('setTimeout');
})
new Promise(function(resolve) {
console.log('promise');
}).then(function() {
console.log('then');
})
console.log('console');
setTimeout
为异步宏任务,扒拉到宏任务列表
new Promise
同步事件,立即执行,因此触发console.log(promise)
then
为异步微任务,扒拉到微任务列表
console.log('console')
同步事件,立即执行,因此触发console.log(console)
因此结果为:
promise
console
setTimeout
//因promise没有返回值 所以then不打印
console.log('1'); //1
setTimeout(function() {//2
console.log('2');
process.nextTick(function() {//3
console.log('3');
})
new Promise(function(resolve) {//4
console.log('4');
resolve();
}).then(function() {//5
console.log('5')
})
})
process.nextTick(function() {//6
console.log('6');
})
new Promise(function(resolve) {//7
console.log('7');
resolve();
}).then(function() {//8
console.log('8')
})
setTimeout(function() {//9
console.log('9');
process.nextTick(function() {//10
console.log('10');
})
new Promise(function(resolve) {//11
console.log('11');
resolve();
}).then(function() {//12
console.log('12')
})
})
// 下面数字为注释前的函数
这个情况中↓
1)先同步执行,因此自上而下 执行 1
,7
且 宏任务队列依次是:2
,9
,
微任务依次是:6
,8
则打印:1,7,6,8
2)先执行第一个宏任务 2
,
微任务为3
,5
,
同步任务为4
,
则此时打印2,4,3,5
3)执行第二个宏任务 9
,
微任务为10
,12
,
同步任务为11
,
则此时打印9,11,10,12
所以最后输出结果是1,7,6,8,2,4,3,5,9,11,10,12
,注意,实际情况根据异步返回时间有关
参考↓
这一次,彻底弄懂 JavaScript 执行机制
JS基础——同步异步的区别