JavaScript 引擎、事件循环、任务队列

Souleigh ✨ 等级 1017 0 1

一、先引用别人的一幅图

(很好的概括了JS主线程和任务队列是如何执行的)

JavaScript 引擎、事件循环、任务队列

1.JS引擎和runtime的区别:

  • 引擎:解释并编译代码,让它变成能交给机器人运行的代码(runnable commands);单线程,负责维护任务队列,按照顺序把任务放入函数栈执行。
  • runtime:就是运行环境,它提供一些对外的接口供JS调用,比如,浏览器环境、Node.js环境。不同的runtime,会提供不同的接口,比如,在 Node.js 环境中,我们可以通过require来引入模块;而在浏览器中,我们有window、 DOM。图中的异步处理模块就是runtime提供的,拥有与JS引擎互不干扰的线程。
  • 总结:JS引擎可以理解为主线程,runtime可以理解为其他的线程。

二、函数栈

现在,我们要运行下面这段代码:

function bar() {
    console.log(1);
}

function foo() {
    console.log(2);
    bar();
}

setTimeout(() => {
    console.log(3)
});

foo();

它在栈中的入栈、出栈过程,如下图: JavaScript 引擎、事件循环、任务队列

总结:其实函数的入栈出栈就是当主线程调用到某个函数的时候该函数就入栈,使用JS引擎去解析执行这个函数,等到该函数执行完毕之后就会弹出函数栈。


三、任务队列

Js 中,有两类任务队列:宏任务队列(macro tasks)和微任务队列(micro tasks)。宏任务队列可以有多个,微任务队列只有一个(eg:Promise)。

  • 宏任务:script(全局任务), setTimeout, setInterval, setImmediate, I/O, UI rendering。宏任务是在下一轮的事件循环中才会执行
  • 微任务:process.nextTick, Promise, Object.observer, MutationObserver。微任务在本轮事件循环中执行
  • 执行顺序:主线程 -> 异步任务(微任务 -> 宏任务)

四、浏览器的事件循环

当函数栈为空时,就会从任务队列里面去除任务来执行。浏览器这里,分为三步:

  1. 取一个宏任务来执行。执行完毕后,下一步。(每解决一个宏任务都需要一轮的事件循环)
  2. 取一个微任务来执行,执行完毕后,再取一个微任务来执行。直到微任务队列为空,执行下一步。(微任务的执行都在同一轮的事件循环中)
  3. 更新UI渲染.

Event Loop 会无限循环执行上面3步,这就是Event Loop的主要控制逻辑。其中,第3步(更新UI渲染)会根据浏览器的逻辑,决定要不要马上执行更新。毕竟更新UI成本大,所以,一般都会比较长的时间间隔,执行一次更新。

从执行步骤来看,我们发现微任务,受到了特殊待遇!我们代码开始执行都是从script(全局任务)开始,所以,一旦我们的全局任务(属于宏任务)执行完,就马上执行完整个微任务队列。

看个例子:

console.log('script start');

// 微任务
Promise.resolve().then(() => {
    console.log('p 1');
});

// 宏任务
setTimeout(() => {
    console.log('setTimeout');
}, 0);

var s = new Date();
while(new Date() - s < 50); // 阻塞50ms

// 微任务
Promise.resolve().then(() => {
    console.log('p 2');
});

console.log('script end');

输出如下:

/*** output ***/

// one macro task
script start
script end

// all micro tasks
p 1
p 2

// one macro task again
setTimeout

上面之所以加50ms的阻塞,是因为setTimeoutdelayTime 最少是 4ms. 为了避免认为setTimeout是因为4ms的延迟而后面才被执行的,我们加了50ms阻塞。


五、NodeJs 的 事件循环

NodeJs 的运行是这样的:

  • 初始化事件循环
  • 执行你的主代码。这里同样,遇到异步处理,就会分配给对应的队列。知道主代码执行完毕。
  • 执行主代码中出现的所有微任务:先执行完所有nextTick(),然后在执行其它所有微任务。
  • 开始 Event Loop
收藏
评论区

相关推荐

JavaScript 引擎、事件循环、任务队列
一、先引用别人的一幅图 (很好的概括了JS主线程和任务队列是如何执行的) 1.JS引擎和runtime的区别: 引擎:解释并编译代码,让它变成
JavaScript 和 Node.js 中事件循环
1.JavaScript中事件循环可以参考《JavaScript忍者秘籍第二版》第十三章,讲解的很好。JavaScript中事件循环,主要就在理解宏任务和微任务这两种异步任务。宏任务(macrotask): setTimeOut 、 setInterval 、 setImmediate 、 I/O 、 各种callback、 UI渲染 、messageCh
Java 操作 CMD命令 Java 读取系统类型
Java 操作 CMD命令 Java 读取系统类型 Runtime runtime = null; runtime.getRuntime().exec(command); **EG.** untime.getRuntime().exec("taskkill /F /IM gsftc.exe"); 强制关闭一个进程  IM代表是 键入进程名称 
System、Runtime、Date、Calendar、Math
System 类中的方法和属性都是静态的。 out:标准输出,默认是控制台 in: 标准输入,默认是键盘 获取系统属性信息:Properties getProperties(); 因为Properties是Hashtable的,也就是Map集合的子类对象,那么可以通过map的方法取出集合中的元素,该集合中存储都是字符串,没有泛型定义。 setPr
ASP.NET Core创建Web Api项目使用EF自动迁移多表数据库
2019-08-23 11:07:09 =================== 1\. 项目创建 ======== 1.1 安装   下载.NETCORE SDK 进行安装   下载NETCORE RUNTIME进行安装.   下载[Runtime & Hosting Bundle](https://www.oschina.net/action/G
GitHub上的7个热门TypeScript项目,要不要学一下呢?
TypeScript 是 JavaScript 的一个超集,支持 ECMAScript 6 标准(ES6 教程)由微软开发的自由和开源的编程语言。设计目标是开发大型应用,它可以编译成纯 JavaScript,编译出来的 JavaScript 可以运行在任何浏览器上。 **语言特性** -------- TypeScript 是一种
Google 是如何设计 Ruby Serverless Runtime 的?
![/images/2021-02-01-designing-a-ruby-serverless-runtime/google.png](https://sls-website-ap-guangzhou-6ta8xa7-1259061164.cos-website.ap-guangzhou.myqcloud.com/images/2021-02-01-des
JavaScript零基础入门——(一)什么是JavaScript
JavaScript零基础入门——(一)什么是JavaScript ================================= 写在前面: 『Hello,大家好,我是振丹!从这节课开始,我会慢慢的带大家学习JavaScript的基础,至于进阶部分,有机会我也会专门开专题来讲。有做后端同学会说,现在微软的TypeScript开始火起来了,连Angu
Minikube部署KubeVirt变得更容易了!
随着minikube的最新版本(v1.12)的发布,我们现在可以用一行程序部署KubeVirt。 **部署minikube** 1\. 启动minikube。因为我的主机是Fedora 32,所以我将使用--driver=kvm2,也将使用--container-runtime=crio minikube start --driver=kvm2
Noark入门之内存监控
服务器正常都需要关注内存使用情况 常规获取内存使用情况可以使用Runtime或MemoryMXBean Noark提供了一个内存监控服务,选择了Runtime实现,详情参考 xyz.noark.game.monitor.impl.MemoryMonitorService 在GameServerConfiguration类中添加如下代
Node.js 安装与开发
**Node.js 简介** Node.js是一个Javascript运行环境(runtime),发布于2009年5月,由Ryan Dahl开发,实质是对Chrome V8引擎进行了封装。Node.js对一些特殊用例进行优化,提供替代的API,使得V8在非浏览器环境下运行得更好。 V8引擎执行Javascript的速度非常快,性能非常好。 Node.j
Rails + Bootstrap个人博客搭建的完整过程(1)
**Part 1** -首先最基本的,创建一个新的的project: rails new blog -然后修改source为https://ruby.taobao.com,加入bootstrap的gem到Gemfile: gem 'twitter-bootstrap-rails' 执行bundle install没有错误,但是有一个
Runtime的使用——利用Runtime将字典转成Model
关于runtime的知识已经有很多的讲解(传送门:对runtime的理解 [http://www.jianshu.com/p/927c8384855a](https://www.oschina.net/action/GoToLink?url=http%3A%2F%2Fwww.jianshu.com%2Fp%2F927c8384855a)),但一直不知道run
System类 和 Runtime 类
java程序在不同操作系统上运行时,可能需要取得平台相关属性,或者调用平台本地命令(如windows下sys32和system64下的可执行文件、本地其他语言写的函数等) 来完成特定功能.java提供了System和Runtime两个类来与程序的运行平台交互。 1.System类 --------- 首先,看构造器(constructor),是一个私有的
TypeScript快速入门
TypeScript是JavaScript类型的超集,它可以编译成纯JavaScript。 TypeScript可以在任何浏览器、任何计算机和任何操作系统上运行,并且是开源的。 TypeScript是微软开源的,它有这强大的技术后盾。 ![](https://oscimg.oschina.net/oscnet/3b63ac2b-6b7f-4c49-