javascript中的event loop事件循环详解

前言

javascript是单线程的语言,也就是说,同一个时间只能做一件事。而这个单线程的特性,与它的用途有关,作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?

为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质

这是今天一个朋友发给我的一个面试题,

感觉还挺有意思的,

写个博客以供分享

先看看这个面试题目:

观察下面的代码,写出输出结果

console.log('0')
setTimeout(function () {
 console.log('1');
});

new Promise(function(resolve,reject){
 console.log('2')
 resolve(3)
}).then(function(val){
 console.log(val)
})
console.log(4)

输出结果: “0” “2” 4 3 “1”

今天主要是分析为什么输出结果是这样的?这就和 javascript 的执行机制密切相关了.

Event Queue 和 Event Loop

javascript 是一门单线程的语言, 这就意味着在执行代码的时候, 都只有一个主线程来处理所有的任务.

我们都知道 javascript 包括同步代码和异步代码, 那么 javascript 是怎么处理这两种情况的呢?

  • 同步和异步任务分别进入不同的执行 场所, 同步的进入主线程,异步的进入 Event Table 并注册函数
  • 当指定的事情完成时, Event Table 会将这个函数(回调函数)移入 Event Queue
  • 主线程内的任务执行完毕为空, 会去 Event Queue 读取对应的函数,进入主线程执行
  • 上述过程会不断重复, 也就是常说的 Event Loop(事件循环)

这里我们引进了 Event Queue 事件队列这一概念. 所有异步操作的回调都会进入到这里. 然后等到主线程空闲, 就会从这里调取回调执行.

setTimeout

setTimeout 相信大家都有使用过, 可以延时执行并且是异步执行的.

但是有时候我们得到的结果往往是代码实际执行的时间比我们想要延时执行的时间要久。这又是为什么呢?

这就和我们之前所说的 Event Loop 有关了, 我们可以来具体看下 setTimeout 的执行步骤:

setTimeout(function () {
asyncFn()
}, 1000);

syncFn()
  • asyncFn 将异步执行函数放在 Event Table, 并且开始计时
  • 开始执行 syncFn, 但是 syncFn 可能需要处理的内容很多, 执行时间超过 1 秒, 但是计时还在继续
  • 计时到达 1 秒, setTimeout 延时完成, asyncFn 进入 Event Queue 事件队列, 但是主线程还在执行, 所以只能等待
  • syncFn 执行完成, 此时 asyncFn 从事件队列中进入主线程执行

所以有时候会出现代码实际执行时间比延时时间长的情况。

宏任务和微任务

之前我们说过异步任务会进入到事件队列中, 不同类型的任务会进入到不同的队列中, 比如宏任务会进入到宏任务队列中, 微任务会进入到微任务队列中.

我们只要记住 当当前执行栈执行完毕时会立刻先处理所有微任务队列中的事件,然后再去宏任务队列中取出一个事件。同一次事件循环中,微任务永远在宏任务之前执行

这时候我们就可以解释一开始的代码执行结果了:

  • 主线程执行按顺序代码
  • 遇到 setTimeout, 回调进入到宏任务队列上
  • 遇到 Promise, 立即执行, then 函数进入到微任务队列
  • 同步代码执行结束, 主线程检查是否存在微任务, 发现 then, 执行
  • 微任务执行完毕, 再去查找宏任务 setTimeout, 执行
  • setTimeout 执行结束, 检查是否存在微任务, 不存在, 结束.

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。

(0)

相关推荐

  • js中事件对象和事件委托的介绍

    Ie9以下浏览器中的事件对象是放在全局中的window.event; 解决兼容性:event = event || window.event 事件委托(就是将事件绑定到父级/爷爷级对象上,通过事件对象的target属性来控制子级对象的改变): event.target(点击的目标对象) <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <

  • Node.js EventEmmitter事件监听器用法实例分析

    本文实例讲述了Node.js EventEmmitter事件监听器用法.分享给大家供大家参考,具体如下: Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列. events 模块只提供了一个对象: events.EventEmitter.EventEmitter 的核心就是事件触发与事件监听器功能的封装. 该模块已被node.js默认引,不需要使用require()显示引入. EventEmitter 对象如果在实例化时发生错误,会触发 'error' 事件.当添加新的监

  • JavaScript常用事件介绍

    JavaScript 事件(常用) 网页中的每个元素都可以产生某些可以触发 JavaScript 函数的事件.比方说,我们可以在用户点击某按钮时产生一个onClick 事件来触发某个函数.事件在HTML 页面中定义. 事件举例: 鼠标点击 页面或图像载入 鼠标悬浮于页面的某个热点之上 在表单中选取输入框 确认表单 键盘按键 注意:事件通常与函数配合使用,当事件发生时函数才会执行. 事件三要素 事件源.事件.事件驱动程序. 三句话:获取事件源.绑定事件.书写事件驱动程序. 1.获取事件源:docu

  • Javascript中绑定click事件的四种方式介绍

    一:HTML中添加onclick <button id="vv" onclick="myfunction()" >哈哈</button> 二:JS中定义函数绑定事件! var funcc = function () { alert('我爱编程') } var aa = document.getElementById('vv') aa.onclick = funcc 三:直接定义函数与内容 document.getElementById('vv

  • JS监听事件的叠加和移除功能

    html DOM元素有很多on开头的监听事件,如onload.onclick等,见DOM事件列表.但是同一种事件,后面注册的会覆盖前面的: window.onresize = function(){ alert(1); } window.onresize = function(){ alert(2); } // 改变窗口大小时,只会弹出2 addEventListener监听 利用addEventListener添加监听事件,可以重复添加,并不会互相覆盖: window.addEventList

  • 浅谈Vue.js 中的 v-on 事件指令的使用

    v-on 事件指令用于绑定事件. 1 基础用法 v-on 指令绑定事件后,就会监听相应的事件. html: <div id="app"> <h3>已点击 {{count}} 次</h3> <button @click="count++">点我</button> </div> 注意: @click 是 v-on:click 的简写形式, @ 即表示 v-on: . js: <script&g

  • JavaScript键盘事件常见用法实例分析

    本文实例讲述了JavaScript键盘事件常见用法.分享给大家供大家参考,具体如下: JavaScript 键盘事件有以下3种 keydown 键盘按键按下(如果按着不放,会持续触发该事件),可以捕获组合键. keypress 键盘非功能按键按下(在keydown之后触发,如果按着不放会持续触发该事件),只能捕获单个键. keyup 键盘按键弹起,可以捕获组合键. 全局事件对象event event.ctrlKey 功能键"ctrl"键是否按下. event.altKey 功能键&qu

  • JavaScript事件对象深入详解

    本文实例讲述了JavaScript事件对象.分享给大家供大家参考,具体如下: 触发 DOM 上的事件时,会生成一个事件对象 event,它包含着所有与事件有关的信息,诸如导致事件的元素.事件的类型以及其他与特定事件相关的信息.所有的浏览器都支持 event 对象,但支持的方式不同. 1 DOM 中的事件对象 兼容 DOM 的浏览器会将 event 对象传入事件处理程序(DOM0 级与 DOM2 级都支持): var btn = document.getElementById("myBtn&quo

  • JavaScript常见鼠标事件与用法分析

    本文实例讲述了JavaScript常见鼠标事件与用法.分享给大家供大家参考,具体如下: JavaScript 鼠标事件有以下8种 mousedown 鼠标的键钮被按下. mouseup 鼠标的键钮释放弹起. click 鼠标左键(或中键)被单击. 事件触发顺序是:mousedown -> mouseup -> click dblclick 鼠标左键(或中键)被双击. 事件触发顺序是:mousedown -> mouseup -> click -> mousedown ->

  • Node.js net模块功能及事件监听用法分析

    本文实例讲述了Node.js net模块功能及事件监听用法.分享给大家供大家参考,具体如下: net模块 对比C语言的网络编程,Node.js有更加简便的开发模式与模块提供.它就是net模块 在需要使用的时候只需要require("net")就可以引入模块了. var net = require("net"); 服务端编程 引入模块的前提下: 1. 创建一个新的TCP或IPC服务 var server = net.createServer(function(clie

随机推荐