2019-03-23T14:23:29.000Z
学习JavaScript引擎执行机制
此博文用于记录学习浏览器的JavaScript引擎执行机制的一些知识点,可用于解决以下的问题:
- JavaScript是单线程语言,是如何实现异步的?
- JavaScript引擎的event loop机制是怎样的?
- 谈谈 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