博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Event Loop
阅读量:4633 次
发布时间:2019-06-09

本文共 2544 字,大约阅读时间需要 8 分钟。

Event Loop

为什么JavaScript是单线程

其最初的用途来决定的:与浏览器交互。

试想一下 如果javascript是多线程的,那么当两个线程同时对dom进行一项操作,例如一个向其添加事件,而另一个删除了这个dom,此时该如何处理呢?因此,为了保证不会 发生类似于这个例子中的情景,javascript选择只用一个主线程来执行代码,这样就保证了程序执行的一致性。
一切javascript版的"多线程"都是用单线程模拟出来的,一切javascript多线程都是纸老虎!

宏任务(macro-task)和微任务(micro-task)

JavaScript的事件分两种,宏任务(macro-task)和微任务(micro-task)

  • 宏任务:包括整体代码script,setTimeout,setInterval, setImmediate(node独有), I/O, UI rendering
  • 微任务:Promise.then(非new Promise),process.nextTick(node独有),Object.observe(废弃), MutationObserver

  • async函数使用==await以后得所有语句会被放入一个回调函数中,放入微任务中==
  • 2个微任务的优先级,==promise高于async==

浏览器js引擎事件循环机制

事件的执行顺序的基础是 ==先执行宏任务,后执行微任务==

任务可以有同步任务和异步任务,同步和异步任务分别进入不同的执行"场所"

  1. 同步的进入主线程;
  2. 异步的进入Event Table并注册函数; 异步事件完成后,会将回调函数放入Event Queue中(宏任务和微任务是不同的Event Queue);
  3. 主线程内的任务执行完毕为空,会去Event Queue读取对应的函数。
  4. 回调函数中可能还会包含不同的任务,因此会循环执行上述操作。
  • 宏任务同步代码 => 微任务(队列) => 宏任务(队列)
    => 微任务(队列) ...
setTimeout(function() {    console.log('setTimeout');},1000)new Promise(function(resolve) {    console.log('promise');}).then(function() {    console.log('then');})console.log('console');
  • 首先setTimeout,放入Event Table中,1秒后将回调函数放入宏任务的Event Queue
  • new Promise 同步代码,立即执行console.log('promise'),然后看到微任务then,因此将其放入微任务的Event Queue
  • 接下来执行同步代码console.log('console')
  • 主线程的宏任务执行完毕,接下来要执行微任务,因此会执行Promise.then,到此,第一轮事件循环执行完毕
  • 第二轮事件循环开始,先执行宏任务(的事件队列),即setTimeout的回调函数,然后查找是否有微任务,没有,事件循环结束

事件循环,先执行宏任务,其中同步任务立即执行,异步任务,加载到对应的的Event Queue,所有同步宏任务执行完毕后,如果发现微任务的Event Queue中有未执行的任务,会先执行其中的任务,这样算是完成了一次事件循环。接下来查看宏任务的Event Queue中是否有未执行的任务,有的话,就开始第二轮事件循环,依此类推。

来至于谷友的一到面试题

// script start => async1 start => async2 => promise1 => script end => promise2 => async1 end => setTimeout
  1. 整个代码块作为一个宏任务,进入主线程
  2. 看到函数申明但没有执行,遇到函数console.log执行,输出script start
  3. 遇到setTimeout() ,把它的回调函数放入宏任务(setTimeout1)。

    宏任务 微任务
    setTimeout1
  4. 遇到执行async1(), 进入async的执行上下文之后,遇到console.log输出async1 start
  5. 然后遇到await async2(),由于()的优先级高,所有先执行async2(),进入async2()的执行上下文。
  6. 看到console.log输出async2,之后没有返回值,结束函数,返回undefined,返回async1的执行上下文的await undefined,由于async函数使用await后得语句会被放入一个回调函数中,所以把下面的放入微任务中。

    宏任务 微任务
    setTimeout1 async1=> awati 后面的语句
  7. 结束async1,返回全局上下文,遇到Promise构造函数,里面的函数立马执行, 输出promise1, 之后的回调函数进入微任务

    宏任务 微任务
    setTimeout1 async1=> awati 后面的语句
    ` ` new Promise() => 后的then
  8. 执行完Promise(),遇到console.log,输出script end,这里一个宏任务代码块执行完毕。
  9. 在主线程执行的过程中,事件触发线程会一直监听异步事件,当异步事件处理完成后,把它的回调函数放入事件队列,等待执行。
  10. 主线程现在空闲下来后,执行事件队列中的微任务,然后继续向下执行,遇到new Promise()后面的回调函数,执行代码,输出promise2(这里2个微任务的优先级,promise高于async)。
  11. 看到async1中await后面的回调函数,执行代码,输出async1 end

    宏任务 微任务
    setTimeout1
  12. 此时微任务中的队列为空,开始执行队列中的宏任务,进入一个新的代码块。遇到console.log,输出setTimeout


原文链接:

转载于:https://www.cnblogs.com/topyang/p/11411571.html

你可能感兴趣的文章
名字的漂亮度
查看>>
Python List append()方法
查看>>
产品经理之我见
查看>>
web渗透测试基本步骤
查看>>
把mysql 中的字符gb2312 改为gbk的方法
查看>>
使用Struts2标签遍历集合
查看>>
angular.isUndefined()
查看>>
第一次软件工程作业(改进版)
查看>>
WPF的图片操作效果(一):RenderTransform
查看>>
网络流24题-飞行员配对方案问题
查看>>
Jenkins 2.16.3默认没有Launch agent via Java Web Start,如何配置使用
查看>>
Excel的数据分析—排位与百分比
查看>>
讯飞语音识别Android-Demo
查看>>
UML for Java Programmers之dx实战
查看>>
引入css的四种方式
查看>>
Mysql蠕虫复制
查看>>
pfSense 2.4.3 发布,包含重要的安全修复补丁
查看>>
centos7+ansible自动化工具使用
查看>>
iOS开发UI篇—transframe属性(形变)
查看>>
3月7日 ArrayList集合
查看>>