fe-interview
fe-interview copied to clipboard
[js] 第48天 你对事件循环有了解吗?说说看!
第48天 你对事件循环有了解吗?说说看!
事件循环机制和异步有关。
从阮一峰大佬教程上摘抄的:
单线程模型
JS 引擎有多个线程,但引擎同时只执行一个任务,其他任务都必须在后面排队,即引擎只在一个线程上运行。这个线程称为主线程。
事件循环机制
JS 本身并不慢,慢的是读写外部数据,比如等待 Ajax 请求返回结果。如果等着 Ajax 返回结果出来,再往下执行,就会耗费很长的时间。所以 JS 设计了一种机制,CPU 可以不管 IO 操作,而是挂起该任务,先执行后面的任务,等到 IO 操作返回了结果,再继续执行挂起的任务。
同步任务执行完后,引擎一遍又一遍检查那些挂起来的异步任务是否满足进入主线程的条件。这种循环检查的机制,就叫做事件循环机制。
任务队列
JS 引擎运行时,除了一个正在运行的主线程,还提供一个或多个任务队列,里面是各种被挂起的异步任务。首先,主线程会去执行所有的同步任务,等到同步任务全部执行完,就会去看任务队列里面的异步任务,如果满足条件,那么异步任务就重新进入主线程开始执行,这时它就会变成同步任务。等到执行完,下一个异步任务再进入主线程开始执行。一旦任务队列清空,程序就结束执行。
同步任务和异步任务
程序里面所有的任务可以分成两类:
- 同步任务:没有被引擎挂起,在主线程上排队执行的任务。只有前一个任务执行完毕,才能执行后一个任务。
- 异步任务:被引擎挂起,不进入主线程,而进入任务队列的任务。只有引擎认为某个异步任务可以执行了,该任务才会进入主线程执行。排在异步任务后面的代码,不用等待异步任务结束会马上运行。
-
浏览器事件循环
-
node事件循环
浏览器事件循环分为 微任务
宏任务
- 微任务 Promise
- 宏任务 同步任务
每一次event loop会先执行所有宏任务 然后再执行微任务
settimeout或者ajax这些浏览器api会在其他线程进行 当完成时会将回调任务插入event loop的调用栈,当下一次event loop被执行时 就会执行到该函数
学习了一波,出了一波笔记
https://www.yinzhuoei.com/index.php/archives/112/
大家写得差不多了 我补充一些
- 任务队列中的都是已经完成的异步操作,而不是说注册一个异步任务就会被放在这个任务队列中,在当前的微任务没有执行完成时,是不会执行下一个宏任务的。
- 所以就有了那个经常在面试题、各种博客中的代码片段:
setTimeout(\_ => console.log(4))
new Promise(resolve => {
resolve()
console.log(1)
}).then(\_ => {
console.log(3)
})
console.log(2)
复制代码 setTimeout 就是作为宏任务来存在的,而 Promise.then 则是具有代表性的微任务,上述代码的执行顺序就是按照序号来输出的。 所有会进入的异步都是指的事件回调中的那部分代码 也就是说 new Promise 在实例化的过程中所执行的代码都是同步进行的,而 then 中注册的回调才是异步执行的。 在同步代码执行完成后才回去检查是否有异步任务完成,并执行对应的回调,而微任务又会在宏任务之前执行。 所以就得到了上述的输出结论 1、2、3、4。
这里说错了是先执行微任务再执行宏任务;
- 进入任务队列后是先执行完所有的宏任务
- 判断是否有可执行的微任务
- 执行完微任务后再执行宏任务
浏览器事件循环分为
微任务
宏任务
- 微任务 Promise
- 宏任务 同步任务 每一次event loop会先执行所有宏任务 然后再执行微任务 settimeout或者ajax这些浏览器api会在其他线程进行 当完成时会将回调任务插入event loop的调用栈,当下一次event loop被执行时 就会执行到该函数
setTimeout 就是作为宏任务来存在的,而 Promise.then 则是具有代表性的微任务
js主线程拥有一个执行栈(同步任务)和一个任务队列(宏任务、微任务),主线程会依次执行。 当遇到同步函数时,会先将函数入栈,函数运行结束后再出栈; 当遇到异步任务时,首先这些任务会返回一个值,让主线程不在此阻塞,使主线程继续执行下去,而真正的任务交给浏览器内核去执行,会将该任务事先定义好的函数加入相应的任务队列(宏任务、微任务) 当js主线程清空执行栈之后,会按先入先出的顺序读取微任务队列的回调函数,并将该函数入栈,继续运行执行栈,直至清空执行栈,再去读取任务队列。 当微任务队列中的任务执行完后,会提取宏任务队列中的一个任务加入微任务队列,接着继续执微任务队列,依次执行直至所有的任务执行结束。
js 是单线程语言,在同一时间只能执做一件事情,但是如果说是碰见Ajax请求,或者说是setTimeOut等,如果按照单线程来说,就一直会阻塞下面的代码去执行,所以有了同步任务和异步任务的概念。 js中有一个主线程和一个调用栈(也叫执行栈),所有的任务都会放到执行栈中等待主线程去执行。
js调用栈采用后进先出的原则,当函数执行的时候会被添加到栈顶,当执行栈执行完成后,就会被栈顶移除,直到栈内被清空。
js同步任务会在执行栈中按照顺序等待主线程依次执行,异步任务会在异步任务有了结果后,将回调函数添加到任务队列中,等待主线程空闲也就是执行栈被清空后,被读取到栈内等待主线程的执行。
任务队列是一种先进先出的数据结构(队列) 任务队列中分宏任务和微任务两种,常见的宏任务有script setTimeout setIntelval 常见的微任务有promise.then
事件循环(Event Loop) 当执行栈执行完所有的同步任务后会检查执行栈是否为空,如果为空就去检查微任务队列,如果为空的话就去执行宏任务,如果不为空就一次性执行完微任务。 每次单个宏任务被执行完就去检查微任务队列中是否有微任务,如果有则执行完所有微任务。然后继续执行宏任务,依次循环知道所有任务执行完毕。