节点事件循环如何决定何时切换流?

时间:2016-04-19 04:53:45

标签: node.js

我在Rasbperry pi上使用nodejs来控制其硬件引脚。 我完全假设代码如:

for (..) {
  executeAsyncCode(..)
}

function executeAsyncCode() {
 doAsync1().then(doAsync2()).then(doAsync3())...
}

最终将以executeAsyncCode的每次执行与其他执行完全分离的方式执行,这意味着两个异步执行不会同时运行。但实时验证和使用显示不同。我遇到执行doAsync1(..)一个接一个地调用executeAsyncCode函数的两次执行,并在此期间做了很多混乱。

对于我的使用它显然是一个问题,因为硬件不能并行使用,并且在许多情况下我可能想要执行代码并依赖于不需要锁的事实。 如何限制这些代码不能一起执行?有没有办法知道事件循环将如何执行代码?

2 个答案:

答案 0 :(得分:1)

所有代码将在事件循环开始下一个上下文之前完成执行。这意味着在执行任何异步回调之前,循环将始终执行完成。例如:

for ( var i = 0; i < 100000; i++ ) {
    console.log( 'Hi!' );
    setTimeout( function ( ) { console.log( 'foo' ); }, 0 );
}

// Some synchronous operation that takes a long time 

console.log( 'bar' );

确定性地输出&#39;嗨!&#39; 100000次后跟'bar'然后由于脚本中没有其他内容,事件循环有机会运行其他消息,最后'foo'输出100000次。

如果你想在开始下一个承诺链之前等待第一个承诺链完成,你应该从executeAsyncCode返回一个承诺,以便你可以在完成时启动下一个:

var previousPromise = Promise.resolve();
for (..) {
  previousPromise = previousPromise.then( executeAsyncCode );
}

function executeAsyncCode() {
  return doAsync1().then(doAsync2).then(doAsync3)...
}

答案 1 :(得分:0)

要等待所有异步代码完成再次运行它们之前必须执行.then()内的下一轮。既然你已经在使用promises,你只需要返回链:

function executeAsyncCode() {
  return doAsync1().then(doAsync2).then(doAsync3)...
}

然后executeAsyncCode()本身可以继续.then()

executeAsyncCode()
.then(function(){
    console.log('finished');
});

所以,两个循环是:

executeAsyncCode()
.then(executeAsyncCode);

五个循环将是:

executeAsyncCode()
.then(executeAsyncCode)
.then(executeAsyncCode)
.then(executeAsyncCode)
.then(executeAsyncCode)
.then(executeAsyncCode);

要进行无限循环,您可以使用javascript动画师和游戏程序员使用的旧的setTimeout样式循环技巧。这是一个无限循环:

function executeAsyncCode() {
  doAsync1()
  .then(doAsync2)
  .then(doAsync3)
  .then(executeAsyncCode);
}

可替换地:

function executeAsyncCode() {
  doAsync1()
  .then(doAsync2)
  .then(doAsync3)
  .then(function(){
    executeAsyncCode();
  });
}

第二种语法允许我们编写条件循环:

function executeAsyncCode() {
  doAsync1()
  .then(doAsync2)
  .then(doAsync3)
  .then(function(){
    if (we_should_loop()) {
      executeAsyncCode();
    }
  });
}

我们也可以构造我们的代码,以便我们可以将循环条件作为参数传递。这是一个简单的倒计时循环:

function executeAsyncCode(count) {
  doAsync1()
  .then(doAsync2)
  .then(doAsync3)
  .then(function(){
    count--;
    if (count) {
      executeAsyncCode(count);
    }
  });
}

所以我们可以这样称呼它:

executeAsyncCode(5); // runs 5 loops

这模拟了一个简单的for循环:

function executeAsyncCode(start, end) {
  doAsync1()
  .then(doAsync2)
  .then(doAsync3)
  .then(function(){
    start--;
    if (start < end) {
      executeAsyncCode(start,end);
    }
  });
}

executeAsyncCode(0, 20); // loops 20 times

这试图模仿for循环的大部分功能:

function executeAsyncCode(x, checkfunction, incrementfunction) {
  if (checkfunction(x)) {
    doAsync1()
    .then(doAsync2)
    .then(doAsync3)
    .then(function(){
      executeAsyncCode(incrementfunction(x));
    });
  }
}

所以你可以把它称为for循环:

// loops 10 times like a for loop:
executeAsyncCode(0, function(i){return i<10}, function(i){return i++});