用AI赚第一桶💰低成本搭建一套AI赚钱工具,源码可二开。 广告
# 浏览器的事件循环--Event Loop 同步任务:在主线程上排队执行的任务 ,只有前一个任务执行完毕,才能执行后一个任务; 异步任务:不进入主线程,而进入"任务队列"的任务,只有 "任务队列" 通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。 > (1)所有同步任务都在 主线程 上执行,形成一个 执行栈。 > (2)主线程之外,还存在一个任务队列。只要 异步任务 有了运行结果,就在任务队列之中放置一个事件。 > (3)一旦 执行栈中的 所有同步任务执行完毕,系统就会 读取 "任务队列" ,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。 > (4)主线程不断重复上面的第三步。 主线程 "任务队列" 中读取事件,这个过程是循环不断的,所以整个的运行机制又被称为 事件循环(Event Loop) ## 异步任务:宏任务和微任务 细分:每次单个宏任务执行完毕后, 检查微任务队列是否为空, 如果不为空,会按照先入先出的规则全部执行完微任务后, 清空微任务队列, 然后再执行下一个宏任务,如此循环 >- 一开始整个脚本(script)作为一个宏任务执行 >- 执行过程中同步任务直接执行,异步任务中宏任务进入宏任务队列,微任务进入微任务队列 >- 当前宏任务执行完出栈(stack),检查微任务队列,有则依次执行,直到全部执行完 >- 执行浏览器UI线程的渲染工作 >- 检查是否有Web Worker任务,有则执行 >- 执行完本轮的宏任务,回到2,依此循环,直到宏任务和微任务队列都为空 宏任务: > setTimeout(); setInterval(); setImmediate(Node.js,只有IE10支持) > > requestAnimationFrame() ----- 请求动画帧,保证回调函数在屏幕每一次的刷新间隔中只被执行一次 微任务: > Promise.then、catch 、finally > > await会把后面的代码以微任务的形式放入微队列中,然后跳出async函数,继续执行async函数后面的代码。所以可以将async/await视为promise+generator的语法糖。 > > Object.observe > > MutationObserver --- 原生api中用来监听node节点变化的一个类 > > process.nextTick (Node.js) ## Node和浏览器的事件循环的区别 Event Loop基于libuv库实现,Event Loop每一次循环都需要依次经过六个阶段。每个阶段都有自己的回调队列,每当进入某个阶段,都会从所属的队列中取出回调来执行 - Event Loop的执行顺序为: 外部输入数据-->轮询阶段(poll)-->检查阶段(check)-->关闭事件回调阶段(close callback)-->定时器检测阶段(timer)-->I/O事件回调阶段(I/O callbacks)-->闲置阶段(idle, prepare)-->。。。按照该顺序反复运行 >- timers: 这个阶段执行定时器队列中的回调如 setTimeout() 和 setInterval()。 >- I/O callbacks: 这个阶段执行几乎所有的回调。但是不包括close事件,定时器和setImmediate()的回调。 >- idle, prepare: 这个阶段仅在内部使用,可以不必理会。 >- poll: 等待新的I/O事件,node在一些特殊情况下会阻塞在这里。 >- check: setImmediate()的回调会在这个阶段执行。 >- close callbacks: 例如socket.on('close', ...)这种close事件的回调。 # 题目 ```javascript <script> console.log('----------- start -----------------'); setTimeout(() => { console.log('setTimeout'); }, 0); // 第二个宏任务队列 new Promise((resolve, reject) => { for(var i=0; i<3; i++){ // 第一个宏任务队列: 主线程的js代码 console.log(i); } resolve(); }).then(() => { console.log('Promise实例成功,回调执行'); // 微任务 }); console.log('----------- end -----------------'); </script> /*代码执行结果 ----------- start ----------------- 0 1 2 ----------- end ----------------- Promise实例成功,回调执行 setTimeout */ ``` 第二题: ```javascript async function async1(){ console.log('1') await async2() console.log('2') } async function async2(){ console.log('3') } console.log('4') setTimeout(function(){ console.log('5') },0) async1(); new Promise(function(resolve){ console.log('6') resolve(); }).then(function(){ console.log('7') }) console.log('8') // 答案: 4,1,3,6,8,2,7,5 ``` 解析: 1.先打印4,这个就不说了; 2.走到setTimeout,是一个宏任务,它要先等当前的宏任务结束后再执行; 3.async1();执行该函数,先打印1,然后执行async2()函数,打印3,因为==async2函数前面有await关键字,会隐式返回promise微任务,进入回调队列==; 4.执行new promise,同步任务,先打印6,后面.then()微任务进入回调队列; 5.打印8,此时同步任务执行完毕,读取任务队列,进入主线程执行; 6.还记得微任务先进先出的顺序吧,此时先执行async2返回的一个promise,打印2; 7.接着到promise.then(),打印出7; 8.到这里当前的宏任务结束,执行下一轮的宏任务setTimeout,所以最后打印出5;