异步代码执行说明

时间:2017-08-17 10:32:18

标签: javascript node.js asynchronous es6-promise

我一直试图解决我遇到的问题,但没有成功,因此我请求你的帮助。

让我们考虑以下示例:

const async = require('async')
var counter = 0

var test = cb => {
  if (++counter < 3) {
    setTimeout( () => {
      async.each([0,1,2], (item, callback) => {
        console.log(item)
        console.log('counter inner ' + counter)
        test(cb)
        callback()
      }, () => {
          cb()
       })
    })
  } else {
      console.log('counter ' + counter)
  } 
}

var prom = new Promise( (res, rej) => test( () => res('done') ) )
prom.then(res => console.log(res))

输出结果为:

0
counter inner 1
1
counter inner 2
counter 3
2
counter inner 3
counter 4
done
0
counter inner 4
counter 5 
1 
counter inner 5
counter 6
2
counter inner 6
counter 7

我不明白的是在第二个counter inner 4之后它是如何打印0的。不应该打印counter inner 1?一个承诺只被解决一次?第二次解决呼叫会发生什么?谢谢。

1 个答案:

答案 0 :(得分:0)

有点难以一步一步地解释它,但我会向后试试 - 意思是从你的输出中我会试着提到代码中的哪一行输出它以及何时。

// obviously starting inside the callback async runs for each of your 3 items

    0 // console.log(item);
    counter inner 1 // console.log('counter inner ' + counter);

    1 // console.log(item);
    counter inner 2 // console.log('counter inner ' + counter);
    counter 3 // let's not forget you also call callback() for each item 
             // which evaluates this condition if (++counter < 3) and starting from here,
             // it will be true and will run your else statement
             // console.log('counter ' + counter);

    2 // console.log(item);
    counter inner 3 // console.log('counter inner ' + counter);
    counter 4 // console.log('counter ' + counter);

// at this point your promise is already resolved (and yes, only once)
    done // prom.then(res => console.log(res))

// Now you are probably questioning where the following output comes from
// remember this condition? if (++counter < 3)
// before starting to evaluate to false and printing to console, once it
// evaluated to true so setTimeout was called with your async callback
// which scheduled it to run on the next "tick"*, which is right after the
// promised was resolved

    0
    counter inner 4
    counter 5 
    1 
    counter inner 5
    counter 6
    2
    counter inner 6
    counter 7

这是setTimeout()超时为0的效果。它就像C中的线程/进程产量。虽然它似乎说“立即运行”,但实际上它会在执行队列的末尾重新排队新的javaScript代码。

根据setTimeout文档,其第二个参数如下:

  

计时器应该以毫秒(千分之一秒)为单位的时间   在执行指定的函数或代码之前等待。如果这   省略参数,使用值0,表示执行   “立即”,或更准确地说,尽快。请注意   无论哪种情况,实际延迟可能比预期的长;

在这里,您可以阅读有关reasons for delays longer than specified的更多信息。

您可以通过将if条件更改为if(++counter < 2)来轻松验证我刚刚解释的内容。由于它永远不会评估为true,因此您将看到控制台输出在"done"停止。