time 0
什么叫执行栈?
程序放里面一个一个的执行,在这里面执行的任务有同步代码,宏任务的异步代码
宏任务队列中的代码放入执行栈是有条件的,事件环走一圈放进去一个,比如ajax放入执行栈的条件是什么,ajax请求的响应回来了,被ajax收到了,setTimeout时间到了,用户交互事件方式时,一个环,一次环运行,只能放一个任务进来
time 2m09s
宏任务队列中先进先出,第一个放进宏任务得到事件,会第一个放进js执行栈中运行。不会反之,如果有多个setTimeout一个100ms、一个200ms,100ms的应该先运行,它先放入宏任务队列,所以得先进先出
time 2m54s
执行栈中的代码执行完毕后,看微任务里面有没有东西,先看promise then里面的,微任务里面的所有任务需要一次清空,它不像宏任务一样一次只执行一个,清空一个,微任务是每一次执行完毕都会去清空所有的微任务
微任务清空完毕了会走gui渲染线程
之后,宏任务队列取出最上面的一个宏任务的回调,放进执行栈,之后又看微任务,因为可能setTimeout里的回调里面有微任务,所以是通过走微任务,判断微任务队列里面有没有任务,是否为空来判断有没有微任务,所以走微任务队列有两个作用,1判断有没有微任务,相当与if()2有,执行队列里面的微任务,知道都执行完毕,清空所有微任务
题目
题目1
time 7m03s
index.js
document.body.style.backgroundColor = 'orange';
console.log(1);
setTimeout( ()=> {
document.body.style.backgroundColor = 'green';
console.log(2);
},0)
Promise.resolve(3).then(num=>{
document.body.style.backgroundColor = 'purple';
console.log(num);
});
console.log(4);
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script src="./index.js"></script>
</body>
</html>
事件触发线程event loop
第一步
运行html,引入代码,运行代码,js引擎线程
先把script(index.js中所有代码)放入js引擎线程执行栈中
js引擎线程开始处理代码,这时候都没有发生预编译,因为之前js引擎线程刚刚得知要运行这个代码,刚刚得到(要运行的)代码,没有执行代码
<script src="./index.js"></script>
开始执行
现在开始执行代码了,之后依次运行index.js中的代码
document.body.style.backgroundColor = ‘orange’;是同步代码直接运行,改变背景颜色变成了orange,改变body的内联style属性
,代码运行生效了,html改变了,但视觉效果不会变,因为js引擎线程运行时,gui渲染线程不会运行,没有走渲染,视觉效果没有改变
time 9m43s
setTimeout运行,宏任务队列里面拿到的不是setTimeout函数,而是setTimeout里传入的回调函数cb
在这里面等100ms,cb进入宏任务队列
time 11m34s
Promise.resolve(3)与console一样是同步任务,.then中的是异步任务Promise是一个微任务,异步任务,但前提是处理回调函数的时候,内部回调函数的时候,比如resolve、reject,then中的函数
promise是个微任务,但是不一定进队列,进队列一定是then运行的时候,这里Promise.resolve(3)执行之后,then才能执行
then执行,then是同步任务,但then里面的cb是微任务
time 13m50s
console.log(4)运行,放入调用栈,打印4
time 15m01s
这时候同步代码执行完毕了,调用栈中没有任何任务,开始执行微任务队列里的任务,全部把微任务队列里面的任务执行完毕,清空
time 15m06s
微任务队列中的任务全部执行完成了,清空微任务
微任务空了,gui渲染线程开始运行、执行,渲染html界面,颜色改变
time 15m15s
宏任务队列中的任务开始执行,setTimeout 中回调函数cb运行,先放入执行栈
setTimeout中的回调函数在调用栈执行,改变了内联元素style中的内容,gui就需要执行了
微任务队列为0->gui渲染线程执行,颜色改变了
总结
整个script是宏任务,宏任务里面可以有同步任务,微任务,宏任务都可以有
1执行栈里面全部代码执行、所有任务执行
2微任务队列里面所有任务执行
3gui渲染
4宏任务队列最上面任务放入执行栈
5执行栈执行里面全部代码,其实和一是一样的
周而复始,直到执行栈、微任务队列(栈)、宏任务队列里面所有任务全部都执行完毕了,才会停止
一旦ajax收到请求,或用户点击事件,又有宏任务进入宏任务队列,就继续把宏任务队列中的代码推入执行中执行,继续上述步骤