Nodejs为什么等待仅限于异步功能?

时间:2018-11-26 06:33:29

标签: javascript node.js asynchronous async-await

可能的副本 await is only valid in async function

我是NodeJS的新手,我发现async-await的概念有点令人困惑。 经过一番阅读和摸索,这是我对同样的理解。

假设我有一个像这样的函数sum

function sum(a, b) {
  // print the numbers
  for (var i = 0; i < 100000; i++) {
    console.log(i);
  }
  // settimeout
  new Promise (resolve => {
    setTimeout(resolve, 1000);
  });
  return a+b;
}

function main() {
  let a = sum(5,2);
  console.log(a);
}

main();

它为计时器分配一个新线程,并继续正常的流程。它首先打印所有数字,返回7,然后等待1秒钟后退出。

但是现在我要按行的顺序执行。将await关键字放在计时器Promise之前很有意义。

async function sum(a, b) {
  // print the numbers
  for (var i = 0; i < 100000; i++) {
    console.log(i);
  }
  // settimeout
  await new Promise (resolve => {
    setTimeout(resolve, 1000);
  });
  return a+b;
}

问题1:在这里,我不理解使用async来使用await的义务。仅放置async只会使函数返回Promise而不是值。流量不变。在打印7之前,它仍会打印所有数字。

问题2:我认为函数前的单词async会误以为函数调用将是异步的,尽管不是。关于设计有任何澄清吗?

问题3:

  • NodeJS中,没有同步或异步功能调用的概念,除非我们有一些阻止功能,例如计时器,远程请求和IO操作。这就是async-await概念的体现。否则,即使程序具有Promises,它也只是一个线程。
  • 在函数之外放置async只会使其返回Promise而不是值。它不会改变程序流程。也许,这只是增加了一些额外的机制来处理await(如果有)只是一个猜测!
  • async不一定使任何函数(或其调用)都异步。除非包含另一个async使其保持等待状态,否则调用具有Promise关键字的函数仍将是同步的。这就是await进入的地方。

我的理解是否正确?

3 个答案:

答案 0 :(得分:3)

您的函数不是一个很好的例子,因为返回值与await结果没有任何关系。因此,Promise的使用是无关紧要的,因为没有它就可以重写代码。让我们稍微改变一下功能,以便它实际上在promise中生成结果:

function sumLater(a, b) {
  return new Promise(resolve => {
    setTimeout(() => resolve(a+b), 1000);
  });
}

async function sum(a, b) {
  // print the numbers
  for (let i = 0; i < 100000; i++) {
    console.log(i);
  }
  // settimeout
  let result = await sumLater(a, b);
  // using the awaited result
  console.log("The awaited result is", result);
  return result;
}

async极大地改变了内部执行函数的方式。一方面,使用承诺的函数无法返回在承诺内生成的值。以同样的方式,任何包含await的函数都不能返回从await开始生成的任何内容,而不会将它们包装在promise中。其原因是当前的计算体系结构中缺少时间旅行。如果一个函数可以 now 返回一个将在两个小时后 完成的操作的结果,那将是一个相当不错的突破。

async不仅向JavaScript引擎发出信号,表明该函数将以这种特殊方式执行,还向人类代码阅读器发出信号,即它返回Promise,而不是返回值(除非返回值)首先已经是一个承诺,不需要包装。

您的大多数问题都归因于术语混乱。不要被术语的字面意义所困扰。 JavaScript中的所有内容(Web Workers除外)都不是同时发生的,乍一看,同时和同步应该是同义词。在JavaScript中,就我所见,同步的意思是“完全在同一任务中执行”,异步的意思是“将新任务放置在执行堆栈中”,或多或少。从这个角度看,async 确实表示该函数将是异步的,因为JavaScript中的含义是“异步”。

答案 1 :(得分:2)

仅使用async-await做出返回承诺或promise并不会真正使函数异步。 async-await或promise用于处理Java的真正异步功能

异步函数只能设置setTimeout,setInterval,requestAnimationFrame和其他函数,有关异步函数的更多信息,请查看这篇文章How to Create asynchronous function in javascript?

将使用两个示例来说明这一点,一个示例使用async-await,另一个示例使用promise,它们之间有什么区别:

  1. 承诺:

```

function main() {
    return new Promise( resolve => {
       console.log(1);
       resolve(true);
    });
}

main()
.then( result => {    // result will have whatever main promise will resolve.
    console.log(2);
});

console.log(3);

```

如果使用promise或返回promise将使函数异步,则输出顺序将为

3
1
2

但是,仅返回promise不会使函数异步,因此输出为

1
3
// Asynchronous happen here
2

现在为什么2后3?,因为只有Javascript异步函数可以异步并进入调用栈,然后进入事件队列,所以.then( function() {})的回调函数才是javascript的真正异步函数。因此,这种行为。 注意,调用main()会返回一个Promise函数。这将用于Promise和async-await之间的区别。

  1. 异步等待

```

async function main() {
    console.log(1);
    return true;
}

main()
.then( result => {  // Result have whatever main function return.
    console.log(2);
});

console.log(3);

```

与此类似,也将打印

1
3
// Asynchronous happen here
2

异步等待和承诺之间有什么区别? async-await只能使用await处理promise,并且任何不返回promise并使用回调函数的异步函数(例如setTimeout,setInterval,request.js,https.js函数等)都不能执行用async-await处理。要处理此类函数,我们只能使用Promise,因为Promise使用回调函数,因此可以处理任何异步函数:

function timeout() {
    return new Promise( (resolve, reject) => {
        console.log(1);
        setTimeout( function() {
            console.log(2);
            resolve(true);
        }, 1000);
    });
}

async function main() {
    console.log(3);
    let result = await timeout();
    console.log(4);
    return result;
}

main()
.then( result => {
    console.log(5);
});

console.log(6);

如预期的那样,到达异步函数setTimeout时,回调函数被推到事件队列并继续处理,再次等待是异步的(不是函数,但其行为类似于.then() )推送到事件队列。其余所有继续,因此输出为:

3
1
6
// asynchronous happens here
2
4
5

最后一个示例详细说明了有关等待的信息,从上一个示例中删除了setTimeout的使用:

function timeout() {
    return new Promise( (resolve, reject) => {
        console.log(1);
        console.log(2);
        resolve(true);
    });
}

async function main() {
    console.log(3);
    let result = await timeout();
    console.log(4);
    return result;
}

main()
.then( result => {
    console.log(5);
});

console.log(6);

预期输出:

3
1
2
6
// Asynchronous await here
4
5

由于async-await等待诺言解析,因此不能与回调异步函数一起使用,否则async-await使代码更清晰漂亮,并减少.then()的回调链。 Promise必须用于使回调异步函数并防止回调地狱。

答案 2 :(得分:0)

它仍然是javascript,这意味着它们仍在单个线程上运行。 await关键字在该行暂停async函数的执行,直到该行可能有一个值解析为止,此时该函数内的执行将继续。您看到所有数字都第一次打印的原因是,该代码在任何异步调用之前。在两个示例中,执行似乎都相同,因为打印100000日志所需的时间比承诺解决所需的时间长得多。