JS运行机制

简介: 本文阐述了浏览器端和node端的js运行机制执行的过程,还进行了两者的运行机制比较,以及同步任务和异步任务的说明,两种异步任务的必要性,以及各自有哪些回调,部分回调的优先级。

网络异常,图片无法展示
|

本文阐述了浏览器端和node端的js运行机制执行的过程,还进行了两者的运行机制比较,以及同步任务和异步任务的说明,两种异步任务的必要性,以及各自有哪些回调,部分回调的优先级。


JS运行机制复述


首先js执行,会有一个函数执行栈(stack),一个任务队列(task queue),一个微任务队列(microtask queue),事件循环(event loop)。


  • 主线程:函数执行栈用来存放同步任务,按照后进先出的顺序执行;
  • 在任务队列中,存放的是宏任务。
  • 当函数执行栈为空时,会启动事件循环机制,将任务队列放到执行栈中执行。在此之前,每从任务队列中取一个任务时,如果微任务队列中存在任务,就先把微任务执行完成,在执行任务队列中的任务。
  • 依次循环,直到任务队列、微任务队列、函数执行栈均为空。


网络异常,图片无法展示
|


附:

同步任务:在主线程上执行的任务,只有前一个任务执行完成后才能执行下一个任务。

异步任务:不进入主线程执行,而是进入到任务队列(task queue)中执行。


Node.js中的事件循环


上段讲的是浏览器端的事件轮询,而node是多线程机制,由libuv库负责Node API的执行,将它分配给不同的线程,形成一个事件循环。

node中事件循环(event loop)大致分为六个部分。


  • timer定时器:执行setTimeout以及setInterval的回调。
  • I/O回调:处理网络、流、tcp错误等回调
  • idle空转和prepare阶段:node内部使用
  • poll轮询:执行poll中的I/O队列,检查定时器是否到时
  • check检查:存放setImmediate回调
  • close回调:关闭的回调


主要的是timer定时器、poll轮询、check 检查三大部分。在此我们只做了解。

事件循环过程:


  • 执行全局Script的同步代码。
  • 执行完同步代码调用栈清空后,执行微任务。先执行NextTick队列(NextTick Queue)中的所有任务,再执行其他微任务队列中的所有任务。
  • 开始执行宏任务,上面6个阶段。从第1个阶段开始,执行相应每一个阶段的宏任务队列中所有任务。(每个阶段的宏任务队列执行完毕后,开始执行微任务),然后在开始下一阶段的宏任务,依次构成事件循环。
  • timers Queue -> 执行微任务 -> I/O Queue -> 执行微任务 -> Check Queue 执行微任务 -> Close Callback Queue -> 执行微任务 ...


浏览器和Node端事件循环的差别


  • 两者的运行机制完全不同,实现机制也不同。
  • node.js可以理解成4个宏任务队列(timer、I/O、check、close)和2个微任务队列。但是执行宏任务时有6个阶段。
  • node.js在开始宏任务6个阶段时,每个阶段都将该宏任务队列中所有任务都取出来执行,每个阶段的宏任务执行完毕后,开始执行微任务。但是浏览器中的事件循环,是只取一个宏任务执行,然后看微任务队列是否存在,存在执行微任务,然后再取一个宏任务,构成循环。



JS异步任务


js的异步任务分为两种:宏任务、微任务。一个宏任务里面可以拥有多个微任务,在执行js代码块的时候才会去执行内部的微任务。


宏任务


macrotask,也叫tasks。一些异步任务的回调会依次进入宏任务队列,等待后续背调用。

宏任务包括:


  • setTimeout/setInterval
  • setImmediate(Node独有)
  • requestAnimationFrame(浏览器独有)
  • I/O
  • UI rendering(浏览器独有)


注意:

1、setTimeout延迟时间为0,与requestAnimationFrame比较:requestAnimationFrame优先级大于setTimeout

2、setTimeout延迟时间为0,与setImmediate比较:不确定

setTimeout(() => console.log('setTimeout'), 0)
setImmediate(()=>{
  console.log('setImmediate');
})


解释:


timer前的准备时间超过1ms,(loop到timer的时间大于1ms),则执行timer阶段(setTimeout)的回调函数。


timer前的准备时间小于1ms,则先执行check阶段(setTimeout)的回调函数,下次事件循环,再执行timer阶段的回调函数。


如果想要setImmediate先执行,可以使用fs文件包裹,确保在I/O回调阶段执行。这样时间循环,会先执行chack阶段,之后再执行timer阶段。


node版本中的setTimeout


setTimeout(() => {
  console.log(1)
})
setTimeout(() => {
  console.log(2)
  Promise.resolve().then(function () {
    console.log('promise')
  })
})
setTimeout(() => {
  console.log(3)
})


  • node11以后的版本与浏览器端运行结果一致:1 2 promise 3。
  • node11之前的版本,执行结果为:1 2 3 promise。它会先进入timer阶段,执行第一个setTimeout并打印。再执行第二个setTimeout并打印,并将Promise放入微任务队列中。然后执行第三个setTimeout并打印。事件循环在执行下一阶段时,先执行微任务队列,打印promise。


微任务


microtask,也叫jobs。除宏任务外的一些异步回调会依次进入微任务队列,等待后续被调用。 微任务包括:


  • process.nextTick(Node独有)
  • Promise.then()
  • Object.observe
  • MutationObserve


注意:

process.nextTick优先级高于Promise.then()。


两种异步任务的必要性


在异步任务队列中,遵循先进先出的原则。此时,在众多异步任务中,如果存在优先级较高的任务需要优先执行,那么只有一个异步任务队列是无法满足的,此时就需要引入微任务队列,将优先级较高的任务放到微任务队列中。如果微任务队列非空,则执行微任务队列,否则执行宏任务队列。


如果只有一种异步任务,那么优先级高的异步任务无法优先执行。


补充


async/await


async/await本质上还是基于Promise的一些封装

async函数在await之前的代码都是同步执行的,可以理解为await之前的代码属于new Promise时传入的代码,await之后的所有代码都是在Promise.then中的回调

目录
相关文章
|
2月前
|
存储 JavaScript 前端开发
深入理解JavaScript中的事件循环(Event Loop):机制与实现
【10月更文挑战第12天】深入理解JavaScript中的事件循环(Event Loop):机制与实现
80 3
|
3月前
|
JavaScript 安全 前端开发
乾坤js隔离机制
乾坤js隔离机制
|
17天前
|
JavaScript 安全 中间件
深入浅出Node.js中间件机制
【10月更文挑战第36天】在探索Node.js的奥秘之旅中,中间件的概念如同魔法一般,它让复杂的请求处理变得优雅而高效。本文将带你领略这一机制的魅力,从概念到实践,一步步揭示如何利用中间件简化和增强你的应用。
|
21天前
|
机器学习/深度学习 自然语言处理 前端开发
前端神经网络入门:Brain.js - 详细介绍和对比不同的实现 - CNN、RNN、DNN、FFNN -无需准备环境打开浏览器即可测试运行-支持WebGPU加速
本文介绍了如何使用 JavaScript 神经网络库 **Brain.js** 实现不同类型的神经网络,包括前馈神经网络(FFNN)、深度神经网络(DNN)和循环神经网络(RNN)。通过简单的示例和代码,帮助前端开发者快速入门并理解神经网络的基本概念。文章还对比了各类神经网络的特点和适用场景,并简要介绍了卷积神经网络(CNN)的替代方案。
|
29天前
|
消息中间件 JavaScript 中间件
深入浅出Node.js中间件机制
【10月更文挑战第24天】在Node.js的世界里,中间件如同厨房中的调料,为后端服务增添风味。本文将带你走进Node.js的中间件机制,从基础概念到实际应用,一探究竟。通过生动的比喻和直观的代码示例,我们将一起解锁中间件的奥秘,让你轻松成为后端料理高手。
28 1
|
2月前
|
JSON JavaScript 中间件
深入浅出Node.js中间件机制
本文将带你探索Node.js中一个核心概念——中间件机制。我们将通过浅显的语言和生动的比喻,揭示中间件如何作为请求和响应之间的“交通枢纽”,在应用程序中起到至关重要的作用。从基础原理到实际应用,你将了解到中间件不仅简化了代码结构,还提高了开发效率,是Node.js开发不可或缺的一部分。
52 1
|
2月前
|
JavaScript 前端开发 开发者
原型链深入解析:JavaScript中的核心机制
【10月更文挑战第13天】原型链深入解析:JavaScript中的核心机制
32 0
|
3月前
|
前端开发 JavaScript Java
JavaScript的运行原理
JavaScript 的运行原理包括代码输入、解析、编译、执行、内存管理和与浏览器交互几个步骤。当打开网页时,浏览器加载 HTML、CSS 和 JavaScript 文件,并通过 JavaScript 引擎将其解析为抽象语法树(AST)。接着,引擎将 AST 编译成字节码或机器码,并在执行阶段利用事件循环机制处理异步操作,确保单线程的 JavaScript 能够高效运行。同时,JavaScript 引擎还负责内存管理和垃圾回收,以减少内存泄漏。通过与 DOM 的交互,JavaScript 实现了动态网页效果,提供了灵活且高效的开发体验。
|
2月前
|
JavaScript 安全 中间件
深入浅出Node.js中间件机制
【10月更文挑战第4天】在探索Node.js的海洋中,中间件机制犹如一座灯塔,为开发者指引方向。本文将带你一探究竟,从浅入深地理解这一核心概念。我们将通过生动的比喻和实际代码示例,揭示中间件如何在请求和响应之间搭建桥梁,实现功能的扩展与定制。无论你是初学者还是有经验的开发者,这篇文章都将为你提供新的视角和深入的理解。
48 0
|
2月前
|
移动开发 JavaScript 前端开发
【JavaScript】JS执行机制--同步与异步
【JavaScript】JS执行机制--同步与异步
21 0