Lin Ya

2019-03-23T14:23:29.000Z

学习JavaScript引擎执行机制

此博文用于记录学习浏览器的JavaScript引擎执行机制的一些知识点,可用于解决以下的问题:

  1. JavaScript是单线程语言,是如何实现异步的?
  2. JavaScript引擎的event loop机制是怎样的?
  3. 谈谈 async/await 和 promise 的执行顺序

JavaScript的单线程特性与异步

为什么JavaScript是单线程的?

首先要考虑到JavaScript设计之初就是为了用于浏览器上。假设: JavaScript是多线程的,当浏览器渲染页面的时候分别有:线程1和线程2,两者同时操作同一个dom节点。 线程1命令删除该节点,而线程2命令编辑此节点。两个线程的指令同时指定给同一个dom节点,且指令是矛盾的,浏览器就不知道怎么执行了。(有点像后端多线程针对同一个数据库资源分别进行读写操作)

为什么JavaScript需要异步?

反向思考,假如JavaScript不支持异步,那么在JavaScript执行的过程中,如果出现某段代码执行时间过长,导致下面的代码被阻塞了,出现长时间的卡死,导致功能不完整,甚至功能不可用,最终给用户很差的用户体验。

有了异步执行,JavaScript可以灵活地处理代码的执行,开发人员在开发的过程中会知道哪些需要同步处理,哪些可以异步处理。

单线程的JavaScript如何实现异步?

JavaScript是通过事件循环机制(event loop)来实现异步的,事件循环机制也就是JavaScript的执行机制(浏览器端和nodejs端的事件循环机制会有一点差别,这里不做展开)。

JavaScript的事件循环机制

同步任务和异步任务?

为了容易的理解,先将JavaScript的任务分为两类:同步任务和异步任务。

JavaScript在执行代码的时候会判断当前任务类型是什么,如果是同步任务则进入主线程中按顺执行,而异步任务则进入任务队列当中,等待JavaScript引擎的调用。当某个异步任务被JavaScript调用的时候,会离开任务队列而进入主线程执行(如果此异步任务有回调函数的话,否则就不需要进入主线程)。

主线程顾名思义就是JavaScript唯一的执行线程,里面的任务是按顺序执行。而任务队列则是异步任务等待执行的地方。

当主线程的任务全部完成了,JavaScript引擎就会检查任务队列中异步任务,是否可以进入主线程了。

宏任务和微任务

到这里就基本认识了JavaScript的循环机制,但实际上并不能简单地将任务划分为同步任务和异步任务两种,而是应该划分为 宏任务微任务

事件循环执行顺序

特点:

  • 宏任务的优先级要高于微任务
  • 每一个宏任务执行完毕都必须将当前的微任务队列清空
  • 第一个 script 标签的代码是第一个宏任务
  • macro-task(宏任务):包括整体代码script,setTimeout,setInterval
  • micro-task(微任务):Promise,process.nextTick

参考链接: