浅谈JavaScript事件循环机制EventLoop-阿里云开发者社区

开发者社区> Villin> 正文

浅谈JavaScript事件循环机制EventLoop

简介: 今天简单说下js的事件循环机制,我们都知道,javascript是单线程语言,它的核心,也是因为它的单线程。有很多小白不清楚EventLoop到底是什么,按照中文翻译,就是事件循环,那js到底是怎样将同步和异步进行处理的。
+关注继续查看

今天简单说下js的事件循环机制,我们都知道,javascript是单线程语言,它的核心,也是因为它的单线程。
有很多小白不清楚EventLoop到底是什么,按照中文翻译,就是事件循环,那js到底是怎样将同步和异步进行处理的。
这篇文章,就简单说一说,js的单线程处理,也就是同步和异步的代码是怎样走向的。

一、同步和异步:
所有的线程,都是有同步队列,和异步队列,立即执行的任务队列,这些都是属于同步任务,比如一个简单的函数;那么像请求接口发送ajax,发送promise,或时间计时器等等,这些就是异步任务。

二、任务队列-事件循环:
同步任务会立刻执行,进入到主线程当中,异步任务会被放到任务队列(Event Queue)当中。Event Queue 单词的意思就是任务队列。等待同步代码执行完毕后,返回来,再将异步中的任务放到主线程中执行,反复这样的循环,这就是事件循环。也就是先执行同步,返回来按照异步的顺序再次执行
image

我们看下面这个代码会打印出什么:

console.log('开始111');

setTimeout(function() {

  console.log('setTimeout111');

}, 0);

Promise.resolve().then(function() {

  console.log('promise111');

}).then(function() {

  console.log('promise222');

});

console.log('开始222');

我们猜想一下上面的代码,会怎样打印?我们知道,肯定是先走同步的代码,从上往下,先打印 “开始111”,再打印“开始222”。
中途的三个异步,进入到了异步队列,等待同步执行完(打印完),返回来再执行异步,所以是后打印出来。
打印的结果先放一放,我们稍后回来再说。现在我们中途插播一段知识点:

三、宏观任务和微观任务(先执行微观任务,再执行宏观任务):

在事件循环中,每进行一次循环操作称为tick,tick 的任务处理模型是比较复杂的,里边有两个词:分别是 Macro Task (宏任务)和 Micro Task(微任务)。

简单来说:

宏观任务主要包含:setTimeout、setInterval、script(整体代码)、I/O、UI 交互事件、setImmediate(Node.js 环境)

微观任务主要包括:Promise、MutaionObserver、process.nextTick(Node.js 环境)

规范:先执行微观任务,再执行宏观任务

那么我们知道了,Promise 属于微观任务, setTimeout、setInterval 属于宏观任务,先执行微观任务,等微观任务执行完,再执行宏观任务。所以我们再看一下这个代码:

console.log('开始111');

setTimeout(function() {

  console.log('setTimeout111');

}, 0);

Promise.resolve().then(function() {

  console.log('promise111');

}).then(function() {

  console.log('promise222');

});

console.log('开始222');

我们按照步骤来分析下:

1、遇到同步任务,直接先打印 “开始111”。
2、遇到异步 setTimeout ,先放到队列中等待执行。
3、遇到了 Promise ,放到等待队列中。
4、遇到同步任务,直接打印 “开始222”。
5、同步执行完,返回执行队列中的代码,从上往下执行,发现有宏观任务 setTimeout 和微观任务 Promise ,那么先执行微观任务,再执行宏观任务。

所以打印的顺序为: 开始111 、开始222 、 promise111 、 promise222 、 setTimeout111 。

同理,我们再来分析一个代码:

console.log('开始111');

setTimeout(function () {

  console.log('timeout111');

});

new Promise(resolve => {

  console.log('promise111');

  resolve();

  setTimeout(() => console.log('timeout222'));

}).then(function () {

  console.log('promise222')

})

console.log('开始222');

分析一下:

1、遇到同步代码,先打印 “开始111” 。
2、遇到setTimeout异步,放入队列,等待执行 。
3、中途遇到Promise函数,函数直接执行,打印 “promise111”。
4、遇到setTimeout ,属于异步,放入队列,等待执行。
5、遇到Promise的then等待成功返回,异步,放入队列。
6、遇到同步,打印 “开始222”。
7、执行完,返回,将异步队列中的代码,按顺序执行。有一个微观任务,then后的,所以打印 “promise222”,再执行两个宏观任务 “timeout111” “timeout222”。

所以,打印的顺序为:开始111 、 promise111 、 开始222 、 promise222 、 timeout111 、 timeout222 .

先执行主任务,把异步任务放入循环队列当中,等待主任务执行完,再执行队列中的异步任务。异步任务先执行微观任务,再执行宏观任务。一直这样循环,反复执行,就是事件循环机制

扩展【宏观任务和微观任务】:
在宿主(如浏览器)中发起的任务是宏观任务,如setTimeout,js引擎中发起的任务是微观任务,如Promise。js执行时,微观任务优先于宏观任务。

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
C#.NET使用Task,await,async,异步执行控件耗时事件(event),不阻塞UI线程和不跨线程执行UI更新,以及其他方式比较
原文:C#.NET使用Task,await,async,异步执行控件耗时事件(event),不阻塞UI线程和不跨线程执行UI更新,以及其他方式比较 使用Task,await,async,异步执行事件(event),不阻塞UI线程和不跨线程执行UI更新   使用Task,await,async 的异步模式 去执行事件(event) 解决不阻塞UI线程和不夸跨线程执行UI更新报错的最佳实践,附加几种其他方式比较 由于是Winform代码和其他原因,本文章只做代码截图演示,不做界面UI展示,当然所有代码都会在截图展示。
3147 0
Js 的事件循环(Event Loop)机制以及实例讲解
大家都知道js是单线程的脚本语言,在同一时间,只能做同一件事,为了协调事件、用户交互、脚本、UI渲染和网络处理等行为,防止主线程阻塞,Event Loop方案应运而生...
9010 0
javascript练习题-事件
  前端javascript练习题-事件  键盘控制div移动如果需要在页面中移动,要将元素脱离文档流(否则会影响页面布局) js实现代码: var odiv=document.getElementsByTagName("div")[0]; document.
528 0
+关注
Villin
一个前端小白,大家一起学习
30
文章
1
问答
文章排行榜
最热
最新
相关电子书
更多
文娱运维技术
立即下载
《SaaS模式云原生数据仓库应用场景实践》
立即下载
《看见新力量:二》电子书
立即下载