We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
网上看了很多文章说javascript的事件循环,很多都没有对浏览器环境和node环境进行区分,浏览器的事件循环和node环境下的事件循环存在着一定的差异。本篇对浏览器中事件循环做一个总结。
js中的任务分为同步任务和异步任务,同步任务的过程很简单,代码按顺序执行,执行完一行,接着执行第二行,当遇到异步任务时,我们都知道,js并不是阻塞等待异步任务完成后再继续执行后面的任务,js会将异步任务挂起,然后继续执行后面的任务,当一个异步事件返回结果后,js会将这个事件加入与当前执行栈不同的另一个队列,我们称之为事件队列。被放入事件队列不会立刻执行其回调,而是等待当前执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码...,如此反复,这样就形成了一个无限的循环。这就是这个过程被称为“事件循环(Event Loop)”的原因。 通过下面这张图我们可以了解到整个过程。
图中的stack表示我们所说的执行栈,web apis则是代表一些异步事件,而callback queue即事件队列。
我们对异步任务做更进一步的区分。不同的异步任务被分为两类:
前面我们介绍过,在一个事件循环中,异步事件返回结果后会被放到一个任务队列中。然而,根据这个异步事件的类型,这个事件实际上会被放到对应的宏任务队列或者微任务队列中去。并且在当前执行栈为空的时候,主线程会查看微任务队列是否有事件存在。如果不存在,那么再去宏任务队列中取出一个事件并把对应的回调加入当前执行栈;如果存在,则会依次执行队列中事件对应的回调,直到微任务队列为空,然后去宏任务队列中取出最前面的一个事件,把对应的回调加入当前执行栈...如此反复,进入循环。
我们只需记住当当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行。
我们来看一段代码:
setTimeout(function() { console.log('setTimeout'); }) new Promise(function(resolve) { console.log('promise'); }).then(function() { console.log('then'); }) console.log('console'); // 执行结果 // promise // console // then // setTimeout
这道题需要仔细
console.log('a') setTimeout(() => { console.log('b') }, 0) const output = new Promise((resolve) => { resolve() }) output.then((e) => { console.log('c') }).then(console.log('d')).catch(console.log('e'))
setTimeout(() => { console.log(1); }, 0); new Promise((resolve, reject) => { console.log(2); for (let i = 0; i < 10000; i++) { i === 9999 && resolve(); } console.log(4); }).then(() => { console.log(5); }); new Promise(function (resolve) { setTimeout(function () { console.log(6) resolve() }, 0) }).then(() => { console.log(7) }) console.log(8); // 2,4,8,5,1,6,7
The text was updated successfully, but these errors were encountered:
No branches or pull requests
网上看了很多文章说javascript的事件循环,很多都没有对浏览器环境和node环境进行区分,浏览器的事件循环和node环境下的事件循环存在着一定的差异。本篇对浏览器中事件循环做一个总结。
js的特点
我们都知道js是一门单线程,非阻塞的脚本语言。这样设计原因是在于js最初的主要运行环境是浏览器,我们需要进行各种各样的dom操作,如果存在多个线程,试想一下,当有两个线程同时对一个dom进行不同的操作,例如一个向其添加事件,而另一个删除了这个dom。此时以哪个线程的操作为准?基于这样的问题,js选择只用一个主线程来执行代码,这样就保证了程序执行的一致性。
因为js是单线程语言,当遇到异步任务(如ajax操作等)时,不可能一直等待异步操作完成,再继续往下执行,在这期间浏览器是空闲状态,显而易见这会导致巨大的资源浪费。
浏览器下Javascript的事件循环机制
1. 事件循环
js中的任务分为同步任务和异步任务,同步任务的过程很简单,代码按顺序执行,执行完一行,接着执行第二行,当遇到异步任务时,我们都知道,js并不是阻塞等待异步任务完成后再继续执行后面的任务,js会将异步任务挂起,然后继续执行后面的任务,当一个异步事件返回结果后,js会将这个事件加入与当前执行栈不同的另一个队列,我们称之为事件队列。被放入事件队列不会立刻执行其回调,而是等待当前执行栈中的所有任务都执行完毕, 主线程处于闲置状态时,主线程会去查找事件队列是否有任务。如果有,那么主线程会从中取出排在第一位的事件,并把这个事件对应的回调放入执行栈中,然后执行其中的同步代码...,如此反复,这样就形成了一个无限的循环。这就是这个过程被称为“事件循环(Event Loop)”的原因。

通过下面这张图我们可以了解到整个过程。
图中的stack表示我们所说的执行栈,web apis则是代表一些异步事件,而callback queue即事件队列。
2. macro task与micro task
我们对异步任务做更进一步的区分。不同的异步任务被分为两类:
前面我们介绍过,在一个事件循环中,异步事件返回结果后会被放到一个任务队列中。然而,根据这个异步事件的类型,这个事件实际上会被放到对应的宏任务队列或者微任务队列中去。并且在当前执行栈为空的时候,主线程会查看微任务队列是否有事件存在。如果不存在,那么再去宏任务队列中取出一个事件并把对应的回调加入当前执行栈;如果存在,则会依次执行队列中事件对应的回调,直到微任务队列为空,然后去宏任务队列中取出最前面的一个事件,把对应的回调加入当前执行栈...如此反复,进入循环。
我们只需记住当当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行。
我们来看一段代码:
常见面试题
这道题需要仔细
参考文章
The text was updated successfully, but these errors were encountered: