坚持了解节点js的异步行为

时间:2018-11-08 13:01:31

标签: javascript node.js asynchronous ecmascript-6

我正在从this site.学习节点js回调和异步行为。在给出的示例中,我编写了以下代码以更好地理解它。

function callbackTester (callbackFn){
    console.log('From callback tester.');
    callbackFn();
}

function pollingWait(){
    while (true) {}
}

callbackTester(() => {
    console.log('From anonymous function.');
    setTimeout(()=>{
        console.log("I'm waiting!");
    }, 500);
    // pollingWait();
});
console.log('I am the last one');

现在,当我注释掉pollingWait()函数时,它可以正常工作。它给出以下输出:

From callback tester.
From anonymous function.
I am the last one
I'm waiting!

现在,当我注释掉setTimeout函数并添加pollingWait()时,程序进入无限循环。我认为这也是预期的行为,因为节点js是单线程的,无法避免无限循环。那么这种异步行为是如何在后台运行的呢?

如何决定何时继续执行以及何时不继续执行?是否可以使自己的函数像setTimeout一样异步使用?

2 个答案:

答案 0 :(得分:2)

  

我认为这也是一种预期的行为,因为节点js是单线程的并且无法避免无限循环。

Node.js isn't single-threaded anymore,但是只有一个主线程,除非您创建工作线程。

  

那么这种异步行为是如何在后台运行的?

Node.js的主线程在一个循环上工作:您的顶级代码运行并返回,然后所有排队的操作(例如计时器回调)都运行并返回,然后下一个排队的操作运行并返回,等等。 setTimeout的工作方式如下:当计时器触发时,事件循环会看到该事件,并将对计时器回调的调用排队。另请注意,虽然默认情况下Node.js只有一个主JavaScript线程,但这并不意味着Node本身是单线程的。特别是它可能在另一个内部线程上执行I / O处理。

  

是否可以使自己的函数像setTimeout一样异步工作?

仅通过使用已提供异步行为并将其包装的东西。其中包括:

  • setTimeout
  • setImmediate
  • process.nextTick
  • 承诺的thencatch回调

乍一看,您可能会认为async函数会这样做,但实际上并没有:async函数中的代码一直同步运行 直到第一次它等待一个承诺解决方案(或者直到它返回)。因此,异步性实际上与上面的最后一个要点相同:thencatch回调。

不能所做的事情(没有工作线程)就像pollingWait那样忙于等待,因为在忙于等待的线程上什么也不会发生

答案 1 :(得分:0)

尝试一下:

let done = false;

setTimeout(() => {
  done = true
}, 5);

const eventLoopQueue = () => {
  return new Promise(resolve => 
    setImmediate(() => {
      console.log('event loop');
      resolve();
    })
  );
}

const run = async () => {
  while (!done) {
    console.log('loop');
    await eventLoopQueue();
  }
}

run().then(() => console.log('Done'));