【Node.js】 事件循环机制

事件循环机制

事件循环机制(Event Loop)
JavaScript为单线程,怎样处理任务

  1. 处理安排好的任务,按照顺序写进主线程里,等线程执行时,这些任务就是 按照顺序在线程中依次被执行;等所有任务执行完成之后,线程会自动退出。
  2. 处理线程中产生的新任务,运用事件循环机制
    引入循环机制,在线程语句后面添加了一个 for 循环语句,让线程会一直循环执行。
    引入事件,在线程运行过程中,等待用户的操作事件,等待过程中线程处于暂停状态,等接收到用户的操作之后再激活线程,然后继续执行。
  3. 处理其他线程发送过来的任务,运用消息队列
    消息队列:一种数据结构,存放要执行的任务,队列先进先出
  • 在线程之间添加一个消息队列
  • 其他线程产生新任务添加进消息队列尾部
  • 主线程循环地从消息队列头部读取任务
  1. 处理其他进程发送过来的任务
    渲染进程专门有一个 IO 线程 用来接收其他进程传进来的消息,接收到消息之后,会将这些消息组装成任务发送给渲染主线程。
  2. 处理高优先级的任务,运用微任务
    宏任务 macrotask / jobs:消息队列中的任务称为宏任务,每个宏任务中都包含了一个微任务队列,在执行宏任务的过程中,如果 DOM 有变化,那么就会将该变化添加到微任务列表中,这样就不会影响到宏任务的继续执行,因此也就解决了 执行效率 的问题。
    微任务 microtask / task:等宏任务中的主要功能都直接完成之后,这时候,渲染引擎并不着急去执行下一个宏任务,而是 执行当前宏任务中的微任务,因为 DOM 变化的事件都保存在这些微任务队列中,这样也就解决了 实时性问题。微任务和宏任务是绑定的,每个宏任务在执行时,会创建自己的微任务队列
  3. 单个任务执行时间过长,运用回调功能
    因为所有的任务都是在单线程中执行的,所以 每次只能执行一个任务,而其他任务就都处于等待状态。如果其中一个任务执行时间过久,那么下一个任务就要等待很长时间。
    针对这种情况,JavaScript 是通过 回调功能 来规避这种问题的,也就是让要执行的 JavaScript 任务滞后执行。
  • 微任务包括 process.nextTickpromiseMutationObserver,其中 process.nextTick 为 Node.js 独有。
  • 宏任务包括 <script>setTimeoutsetIntervalsetImmediateI/OUI rendering

Event Loop 的执行顺序如下所示:

  • 首先执行执行栈中的 同步代码,这属于宏任务
  • 当执行完所有同步代码后,执行栈为空,查询是否有 异步代码 需要执行
  • 之后执行所有 微任务
  • 当执行完所有微任务后,如有必要会渲染页面
  • 然后开始下一轮 Event Loop ,执行宏任务中的异步代码,也就是 setTimeout 中的回调函数

这里很多人会有个误区,认为微任务快于宏任务,其实是错误的。因为宏任务中包括了 script,浏览器会先执行一个宏任务,接下来有异步代码的话才会先执行微任务。

这一次,彻底弄懂 JavaScript 执行机制

回调

不同的回调执行时机:宏任务和微任务
Event Loop :你知道它们的打印顺序吗?
回调函数:该函数作为一个参数传递给另一个函数
同步回调:在主函数返回之前执行回调函数
异步回调:在主函数外部执行回调函数

  • 第一种就是把异步函数做成一个任务(宏任务),添加到 消息队列 (延迟执行队列或普通的消息队列)的尾部,之后从消息队列取出维护一个新的调用栈去执行。比如 setTimeout 和 XMLHttpRequest 的回调函数。
  • 第二种就是把 异步函数添加到微任务队列 中,这样就是在当前任务(当前调用栈)的末尾处(在主函数执行结束之后、当前宏任务结束之前)执行了。比如 promise,MutationObserver 的回调函数。
//同步回调
function call() {
    console.log('call');
  }
  
function test(callback) {
    console.log('start');
    callback();
    console.log('end');
  }
  
test(call);

// start
// call
// end
//异步回调
function call() {
  console.log('call');
}

function test(callback) {
  console.log('start');
  setTimeout(callback, 0);
  console.log('end');
}

test(call);

// start
// end
// call

(原文有很多例子)

  • promise 比 setTimout 早输出
  • Promise 一旦被定义就会立即执行
  • promise 的 .then 放入等待队列
  • await … ; 这里的 … 执行完就跳出 async ,把await 后面 async 中的语句加到等待队列
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值