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
涉及到多个异步事件执行的时候,大家会不会产生思考!执行顺序,还和原来一样么?还是有什么固定的规则,让我们去判断!今天我们就来了解一下Event Loop的概念。
在聊起这个概念之前,我们先来听一段JavaScript语言的自述。
众所周知,JavaScript是一门单线程的语言。为什么浏览器会去选择它呢!原因就是——简单。在浏览器端,复杂的UI环境会限制多线程语言的开发。例如:
一个线程在操作一个DOM元素的时候,另一个线程需要去删除这个DOM元素。这种情况下,我们就需要进行状态的同步。可怕的是,浏览器往往不止去操作一个DOM元素!所以,为了避免开发中处理这种复杂的情况,单线程语言不失为一种好的解决方案。
但是,单线程也会有它的缺陷——同步阻塞。如图所示:
CPU在进行一个I/O操作的时候,需要去请求数据,期间需要等待数据返回之后,才能够继续执行下面的任务。这个等待期,就阻塞了其他任务的执行。因此,JavaScript在执行过程中,将任务分成了同步任务和异步任务,来解决类似的情况。
每个线程都有一个执行栈,会根据先进后出的顺序来执行线程中的任务,所有的同步任务,都会被放到这个执行栈中,我们可以来看一段代码:
function fun1(){ return 'hello hip-hop'; } function fun2(){ return fun1(); } function fun3(){ console.log(fun2()); } fun3(); //'hello hip-hop'
它的执行顺序如下:
或者我们可以通过浏览器后台的报错来看整个执行顺序,如下:
function fun1(){ throw new Error('hello hip-hop'); } function fun2(){ return fun1(); } function fun3(){ console.log(fun2()); } fun3();
浏览器后台的报错提示,如图:
在此基础上,我们如果加入异步任务,会发生什么样的情况呢,如下:
console.log('first'); setTimeout(() => { console.log('second'); }, 500); console.log('three');
我们依然通过画图的形式,来直观地感受一下执行栈的顺序,如图:
从图中,我们可以清晰地看到setTimeout执行完成之后,就出栈了!那么,后来的console.log('second')是如何入栈的呢?
其实,在主线程之外,还存在一个任务队列。异步任务,都会被放到任务队列中。只有当指定事件触发之后,异步任务才会被放到主线程中执行。
任务队列中,是一个事件队列。拿setTimeout举例来说:
上述流程,规范为一张图如下:
这里有个循环,是一个死循环,无论哪种情况都是闭环,这个就是事件循环。事件循环不断地在检测队列是否存在已触发的任务,如果有的话,就放到主线程中执行(注:这个过程往往在主线程执行完之后进行)。
这幅图里面,我们看到了有浏览器的点击事件、ajax请求、Promise等这里。但是不同之处在于,它们的任务性质存在不同。
自从,ES6出现之后,Promise逐渐被开发者热议。这里我们来讨论一下它这方面的特殊性。
首先,我们来看一段代码:
setTimeout(() => { console.log(1); }, 0); Promise.resolve().then(() => { console.log(2); }).then(() => { console.log(3); }); console.log(4); // 4 2 3 1
你会不会有所疑问,为啥不是4 1 2 3的顺序呢?
其实,这个执行顺序和任务队列有关系!任务队列中存在两种队列类型:宏任务和微任务。宏任务可以有多个队列,微任务只能有一个!同时,宏任务是一个一个出队的,而微任务是一队一队出队的。
在执行事件循环的过程中:
了解清楚这个后,我们再回头看,心中亦如明镜。setTimeout是宏任务,Promise是微任务。具体分类如下:
本文我们回顾了:
希望对于你来说有所收获,感谢阅读。
欢迎您扫一扫上面的微信公众号,订阅我的博客!
The text was updated successfully, but these errors were encountered:
再谈事件循环 JavaScript并发模型与Event Loop
Sorry, something went wrong.
No branches or pull requests
在聊起这个概念之前,我们先来听一段JavaScript语言的自述。
浏览器为什么选择了我
众所周知,JavaScript是一门单线程的语言。为什么浏览器会去选择它呢!原因就是——简单。在浏览器端,复杂的UI环境会限制多线程语言的开发。例如:
一个线程在操作一个DOM元素的时候,另一个线程需要去删除这个DOM元素。这种情况下,我们就需要进行状态的同步。可怕的是,浏览器往往不止去操作一个DOM元素!所以,为了避免开发中处理这种复杂的情况,单线程语言不失为一种好的解决方案。
但是,单线程也会有它的缺陷——同步阻塞。如图所示:
CPU在进行一个I/O操作的时候,需要去请求数据,期间需要等待数据返回之后,才能够继续执行下面的任务。这个等待期,就阻塞了其他任务的执行。因此,JavaScript在执行过程中,将任务分成了同步任务和异步任务,来解决类似的情况。
同步/异步
每个线程都有一个执行栈,会根据先进后出的顺序来执行线程中的任务,所有的同步任务,都会被放到这个执行栈中,我们可以来看一段代码:
它的执行顺序如下:
或者我们可以通过浏览器后台的报错来看整个执行顺序,如下:
浏览器后台的报错提示,如图:
在此基础上,我们如果加入异步任务,会发生什么样的情况呢,如下:
我们依然通过画图的形式,来直观地感受一下执行栈的顺序,如图:
从图中,我们可以清晰地看到setTimeout执行完成之后,就出栈了!那么,后来的console.log('second')是如何入栈的呢?
其实,在主线程之外,还存在一个任务队列。异步任务,都会被放到任务队列中。只有当指定事件触发之后,异步任务才会被放到主线程中执行。
任务队列中,是一个事件队列。拿setTimeout举例来说:
事件循环
上述流程,规范为一张图如下:
这里有个循环,是一个死循环,无论哪种情况都是闭环,这个就是事件循环。事件循环不断地在检测队列是否存在已触发的任务,如果有的话,就放到主线程中执行(注:这个过程往往在主线程执行完之后进行)。
这幅图里面,我们看到了有浏览器的点击事件、ajax请求、Promise等这里。但是不同之处在于,它们的任务性质存在不同。
自从,ES6出现之后,Promise逐渐被开发者热议。这里我们来讨论一下它这方面的特殊性。
首先,我们来看一段代码:
其实,这个执行顺序和任务队列有关系!任务队列中存在两种队列类型:宏任务和微任务。宏任务可以有多个队列,微任务只能有一个!同时,宏任务是一个一个出队的,而微任务是一队一队出队的。
在执行事件循环的过程中:
了解清楚这个后,我们再回头看,心中亦如明镜。setTimeout是宏任务,Promise是微任务。具体分类如下:
总结
本文我们回顾了:
希望对于你来说有所收获,感谢阅读。
欢迎您扫一扫上面的微信公众号,订阅我的博客!
The text was updated successfully, but these errors were encountered: