热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

浏览器的eventloop和node的eventloop

1.什么是eventloopeventloops也就是事件循环,它是为了协调事件(event),用户交互(u

1.什么是event loop

event loops也就是事件循环,它是为了协调事件(event),用户交互(user interaction),脚本(script),渲染(rendering),网络(networking),用户代理(user agent)的工作而产生的一个机制。


2.Javascript的运行机制


2.1 单线程的Javascript

Javascript语言的一大特点就是单线程,也就是说在同一时间只做同一件事。这是基于js的执行环境决定的,因为在浏览器中,有许多的dom操作,如果在同一时间操作一个dom,很容易造成混乱,所以为了避免发生同一时间操作同一dom的情况,js选择只用一个主线程执行代码,来保证程序执行的一致性,单线程的特点也应用到了node中。


2.2 Javascript中的任务和队列

Javascript是单线程的,也就意味着所有任务需要排队,前一个任务执行完,才能执行下一个任务,但是因为IO设备(输入输出设备)很慢(比如Ajax从网络读取数据),不得不等待结果返回之后才能继续,这样的执行效率很慢。
于是分成了两种任务来处理,同步任务和异步任务。
同步任务是指在主线程排队的任务,只有前面的任务执行完之后才执行后面的任务。
异步任务指的是任务不进入主线程,而进入到一个任务队列(task queue),主线程的任务可以继续往后执行,而在任务队列里的异步任务执行完会通知主线程。


3.浏览器的event loop


3.1执行栈与事件队列

当Javascript代码执行的时候会将不同的变量存于内存中的不同位置:堆(heap)和栈(stack)中来加以区分。其中,堆里存放着一些对象。而栈中则存放着一些基础类型变量以及对象的指针。当所有所有同步任务都在主线程上执行时,这些任务被排列在一个单独的地方,形成一个执行栈

当浏览器js引擎解析这段代码时,会将同步任务顺序加入执行栈中依次执行,当遇到异步任务时并不会一直等待异步任务返回结果再执行后面的任务,而是将异步任务挂起,继续执行同步任务,当异步任务返回结果时,将异步任务的回调事件加入到一个事件队列(Task Queue)当中去,这个事件队列里的任务并不会立即执行,而是等同步任务全部执行完,再依次执行事件队列里的事件。

依次执行同步任务,完成后依次执行事件队列,完成后再去执行同步任务,这样形成了一个循环,就是事件循环(Event Loop)。


3.2宏任务(macro task)与微任务(micro task)

异步任务又分为宏任务与微任务两种,微任务并不是老老实实的按照事件队列的顺序去执行,而是按照microTask—>macroTask的顺序去执行,先执行完队列中所有的microTask再去执行macroTask

宏任务和微任务的分类


  • MacroTask: script(整体代码), setTimeout, setInterval, setImmediate(node独有), I/O, UI rendering

  • MicroTask: process.nextTick(node独有), Promises, Object.observe(废弃), MutationObserver

举个例子
setTimeout(()=>{console.log(1)
})
Promise.resolve().then(function() {console.log(2)
})

console.log(3)执行结果是:3 2 1
这是因为事件循环的顺序是:同步代码=>
微任务=>宏任务

4.node的event loop


  • timers: 这个阶段执行定时器队列中的回调如 setTimeout() 和 setInterval()。

  • I/O callbacks: 这个阶段执行几乎所有的回调。但是不包括close事件,定时器和setImmediate()的回调。

  • idle, prepare: 这个阶段仅在内部使用,可以不必理会。

  • poll: 等待新的I/O事件,node在一些特殊情况下会阻塞在这里。

  • check: setImmediate()的回调会在这个阶段执行。

  • close callbacks: 例如socket.on(‘close’, …)这种close事件的回调。


event loop的每一次循环都需要依次经过上述的阶段。 每个阶段都有自己的callback队列,每当进入某个阶段,都会从所属的队列中取出callback来执行,当队列为空或者被执行callback的数量达到系统的最大数量时,进入下一阶段。这六个阶段都执行完毕称为一轮循环。

举个例子(1)
浏览器与Node执行顺序的区别
setTimeout(()=>{console.log('timer1')Promise.resolve().then(function() {console.log('promise1')})
})
setTimeout(()=>{console.log('timer2')Promise.resolve().then(function() {console.log('promise2')})
})

浏览器输出:
time1
promise1
time2
promise2
因为promise是microtask,所以当第一个setTimeout执行完之后,先执行promise。

Node输出:
time1
time2
promise1
promise2
因为time1和time2都在timers阶段,所以先执行timers,promise的回调被加入到了microtask队列,等到timers阶段执行完毕,在去执行microtask队列。

举个例子(2)
MicroTask队列与MacroTask队列
setTimeout(function () {console.log(1);
});
console.log(2);
process.nextTick(() => {console.log(3);
})
;
new Promise(function (resolve, rejected) {console.log(4);resolve()
})
.then(res=>{console.log(5);
})

setImmediate(function () {console.log(6)
})

console.log('end');

node输出的顺序是
2
4
end
3
5
1
6
首先执行的是同步任务中的2 4 end,然后是microTask队列中的process.nextTick:3、promise.then:5,最后是macroTask队列中的setTimeout:1、setImmediate:6,由于Timer优于Check阶段,所以先1后6。


推荐阅读
  • LeetCode笔记:剑指Offer 41. 数据流中的中位数(Java、堆、优先队列、知识点)
    本文介绍了LeetCode剑指Offer 41题的解题思路和代码实现,主要涉及了Java中的优先队列和堆排序的知识点。优先队列是Queue接口的实现,可以对其中的元素进行排序,采用小顶堆的方式进行排序。本文还介绍了Java中queue的offer、poll、add、remove、element、peek等方法的区别和用法。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
  • 本文介绍了如何通过维持两个堆来获取一个数据流中的中位数。通过使用最大堆和最小堆,分别保存数据流中较小的一半和较大的一半数值,可以保证两个堆的大小差距为1或0。如果数据流中的数量为奇数,则中位数为较大堆的最大值;如果数量为偶数,则中位数为较大堆的最大值和较小堆的最小值的平均值。可以使用优先队列来实现堆的功能。本文还提供了相应的Java代码实现。 ... [详细]
  • 第七课主要内容:多进程多线程FIFO,LIFO,优先队列线程局部变量进程与线程的选择线程池异步IO概念及twisted案例股票数据抓取 ... [详细]
  • java线程池的实现原理源码分析
    这篇文章主要介绍“java线程池的实现原理源码分析”,在日常操作中,相信很多人在java线程池的实现原理源码分析问题上存在疑惑,小编查阅了各式资 ... [详细]
  • 关于extjs开发实战pdf的信息
    本文目录一览:1、extjs实用开发指南2、本 ... [详细]
  • 本文介绍了如何使用php限制数据库插入的条数并显示每次插入数据库之间的数据数目,以及避免重复提交的方法。同时还介绍了如何限制某一个数据库用户的并发连接数,以及设置数据库的连接数和连接超时时间的方法。最后提供了一些关于浏览器在线用户数和数据库连接数量比例的参考值。 ... [详细]
  • 如何使用Java获取服务器硬件信息和磁盘负载率
    本文介绍了使用Java编程语言获取服务器硬件信息和磁盘负载率的方法。首先在远程服务器上搭建一个支持服务端语言的HTTP服务,并获取服务器的磁盘信息,并将结果输出。然后在本地使用JS编写一个AJAX脚本,远程请求服务端的程序,得到结果并展示给用户。其中还介绍了如何提取硬盘序列号的方法。 ... [详细]
  • 本文介绍了在Android开发中使用软引用和弱引用的应用。如果一个对象只具有软引用,那么只有在内存不够的情况下才会被回收,可以用来实现内存敏感的高速缓存;而如果一个对象只具有弱引用,不管内存是否足够,都会被垃圾回收器回收。软引用和弱引用还可以与引用队列联合使用,当被引用的对象被回收时,会将引用加入到关联的引用队列中。软引用和弱引用的根本区别在于生命周期的长短,弱引用的对象可能随时被回收,而软引用的对象只有在内存不够时才会被回收。 ... [详细]
  • 第8章 使用外部和内部链接
    8.1使用web地址LearnAboutafricanelephants. ... [详细]
  • Vue基础一、什么是Vue1.1概念Vue(读音vjuː,类似于view)是一套用于构建用户界面的渐进式JavaScript框架,与其它大型框架不 ... [详细]
  • ASP.NET&Spring.NET&NHibernate最佳实践(五)——第3章人事子系统(2)
    3.4.人事子系统服务层(Service)部门服务接口(IDeptService.cs)usingSystem;usingGuushuuse.SalaryPrj. ... [详细]
  • 一、Struts2是一个基于MVC设计模式的Web应用框架在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。Struts2优点1、实现 ... [详细]
  • 一、死锁现象与递归锁进程也是有死锁的所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作 ... [详细]
author-avatar
门前西瓜飘乐
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有