欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

node.js中对Event Loop事件循环的理解与应用实例分析

程序员文章站 2022-07-04 16:53:37
本文实例讲述了node.js中对event loop事件循环的理解与应用。分享给大家供大家参考,具体如下:javascript是单线程的,所以任务的执行都需要排队,任务分为两种,一种是同步任务,一种是...

本文实例讲述了node.js中对event loop事件循环的理解与应用。分享给大家供大家参考,具体如下:

javascript是单线程的,所以任务的执行都需要排队,任务分为两种,一种是同步任务,一种是异步任务。

同步任务是进入主线程上排队执行的任务,上一个任务执行完了,下一个任务才会执行。

异步任务是不进入主线程,而是进入一个 "任务队列" 里,"任务队列" 通知主线程,该异步任务才会进入主线程执行。

任务的运行机制如下:

1、所有同步任务在主线程上执行,形成一个 "执行栈",注意栈是先进后出的。

2、主线程外,有一个 "任务队列" ,只要异步任务处理完有结果了,就在 "任务队列" 中放置一个事件,注意队列是先进先出的。

3、一旦 "执行栈" 中所有同步任务执行完毕。系统读取 "任务队列" 中的事件,对应的异步任务。放入 "执行栈" 中,开始执行。

4、主线程不断重复第三步,这种循环从 "任务队列" 中读取事件处理的这种运行机制称为event loop(事件循环)。

"执行栈" 中的同步代码总是比 "任务队列"中的异步任务之前运行。

function fun() {
  settimeout(function () {
    console.log('异步任务');
  }, 0);
  console.log(1);
  console.log(2);
  console.log(3);
  console.log(4);
  console.log(5);
}
fun();

上面的代码,console.log代码写在settimeout后面,但仍然先执行。

"任务队列" 是一个队列,队列的特性是先进先出。看下面代码:

function fun() {
  console.log(1);
  settimeout(function () {
    console.log(2);
    settimeout(function () {
      console.log(3);
    }, 0);
  }, 0);
  console.log(4);
}
fun();

输出结果为 1  4  2  3,打印 2 的settimeout任务比打印 3 的settimeout任务先进入队列,所以会先运行。

对于异步操作,像ajax,只有操作成功后返回结果,才会进入 "任务队列" 中,而不是调用的时候就放入队列中。看下面代码:

<!doctype html>
<html lang="zh-cn">
<head>
  <meta charset="utf-8">
  <title>title</title>
</head>
<body>
<script>
  function ajax() {
    var xhr = new xmlhttprequest();
    xhr.open('get', 'https://mail.163.com/', true);
    xhr.send();
    xhr.onreadystatechange = function () {
      if (xhr.readystate == 4 && xhr.status == 200) {
        console.log(xhr.responsetext);
      }
    };
  }
  function fun() {
    console.log(1);
    ajax();
    settimeout(function () {
      console.log(2);
    }, 1000);
    console.log(3);
  }
  fun();
</script>
</body>
</html>

ajax() 与 settimeout 谁先进入队列,谁先输出,是需要看两者消耗时间,谁更短。时间短的会先进入队列先运行。

settimeout 与 setinterval 运行机制一样,都是在指定时间把事件插入到 "任务队列" 尾部。区别是前者只执行一次,后者可反复执行。

node.js 还为我们提供了,process.nexttick 和 setimmediate 与 "任务队列" 有关的方法。

process.nexttick 会把回调函数放在当前 "执行栈" 的尾部。也就是说是在读取 "任务队列" 之前运行。

function fun() {
  console.log(1);
  settimeout(function () {
    console.log(2);
  }, 0);
  process.nexttick(function () {
    console.log(3);
    process.nexttick(function () {
      console.log(4);
    });
  });
  process.nexttick(function () {
    console.log(5);
  });
  console.log(6);
}
fun();

上面的代码会输出 1  6  3  5  4  2 ,注意process.nexttick会把回调函数放在 "执行栈" 的尾部。

同步代码最先输出 1  6,然后 3 的先放入尾部,然后 5 的跟在 3 后面。3先执行,然后把 4 放入到 5 的后面。5执行完后,再执行4,最后读取 "任务队列" 中的输出2。

setimmediate 会把回调函数放在当前 "任务队列" 的尾部。也就是下一次事件循环event loop时执行。

function fun() {
  console.log(1);
  settimeout(function () {
    console.log(2);
  }, 0);
  setimmediate(function () {
    console.log(3);
  });
  console.log(4);
}
fun();

上面的代码是会输出 1  4  2  3 还是 1  4  3  2 是不确定的,因为settimeout 与 setimmediate 都会在下一次事件循环event loop中触发,所以输出是不确定的。

希望本文所述对大家node.js程序设计有所帮助。