请执行以下循环:
for(var i=0; i<100; ++i){
let result = await some_slow_async_function();
do_something_with_result();
}
会
await
阻塞循环吗?还是ingi
期间继续await
增加?有关的
do_something_with_result()
保证顺序是顺序的i
吗?还是取决于await
每个功能的ed功能有多快i
?
请执行以下循环:
for(var i=0; i<100; ++i){
let result = await some_slow_async_function();
do_something_with_result();
}
会await
阻塞循环吗?还是ingi
期间继续await
增加?
有关的do_something_with_result()
保证顺序是顺序的i
吗?还是取决于await
每个功能的ed功能有多快i
?
await Promise.all(arr)
,或者这种形式是否正确以及是否有其他原因妨碍了所需的异步性。如果我await
对所有这些都执行一次操作,那么我就必须Promise.map
处理所有这些。这使我怀疑.then
在这种情况下是否比异步/等待更好。
Promise.all
,这样做有什么不同-它是否仍然正确(甚至更理想)取决于您的要求。
async
涉及外部资源(例如数据库,文件I / O)的操作时,函数运行的时间是不确定的。
Answers:
- 会
await
阻塞循环吗?还是ingi
期间继续await
增加?
“阻止”不是正确的词,但是是的,我在等待时不会继续递增。取而代之的是执行跳回到async
调用该函数的位置,提供一个诺言作为返回值,继续执行该函数调用之后的其余代码,直到清空了代码堆栈。然后,等待结束后,功能状态将恢复,并在该功能内继续执行。只要该函数返回(完成),就会解决相应的诺言-早先返回的诺言。
- 有关的
do_something_with_result()
保证顺序是顺序的i
吗?还是取决于await
每个功能的ed功能有多快i
?
订单得到保证。的代码之后的await
也保证调用堆栈已被清空之后才执行,即至少上或之后的下一个microtask可以执行。
查看此代码段中的输出。请特别注意它说“调用测试后”的地方:
async function test() {
for (let i = 0; i < 2; i++) {
console.log('Before await for ', i);
let result = await Promise.resolve(i);
console.log('After await. Value is ', result);
}
}
test().then(_ => console.log('After test() resolved'));
console.log('After calling test');
async/await
直到最近才使用generators /实现的yield
。以这种方式思考使一切变得更加清晰。我会接受这个答案。
then
行为有关,而不是与生成器有关。仅“跳回调用位置”和“功能状态已还原”是yield
。
.then
但不能轻松地看到堆栈模型await
,因此将其视为yield
解决了我的困惑。
正如@realbart所说,它确实阻塞了循环,然后将使调用顺序化。
如果要触发大量等待的操作,然后一起处理所有操作,则可以执行以下操作:
const promisesToAwait = [];
for (let i = 0; i < 100; i++) {
promisesToAwait.push(fetchDataForId(i));
}
const responses = await Promise.all(promisesToAwait);
promisesToAwait
数组将永远不会包含承诺。
没有事件循环未被阻止,请参见下面的示例
function sayHelloAfterSomeTime (ms) {
return new Promise((resolve, reject) => {
if (typeof ms !== 'number') return reject('ms must be a number')
setTimeout(() => {
console.log('Hello after '+ ms / 1000 + ' second(s)')
resolve()
}, ms)
})
}
async function awaitGo (ms) {
await sayHelloAfterSomeTime(ms).catch(e => console.log(e))
console.log('after awaiting for saying Hello, i can do another things ...')
}
function notAwaitGo (ms) {
sayHelloAfterSomeTime(ms).catch(e => console.log(e))
console.log('i dont wait for saying Hello ...')
}
awaitGo(1000)
notAwaitGo(1000)
console.log('coucou i am event loop and i am not blocked ...')
async
函数将返回Promise,这是一个最终将“解析”为值的对象,或最终因错误而“拒绝”的对象。该await
关键字表示要等到这个值(或错误)已经完成。
因此,从运行功能的角度来看,它阻止等待慢速异步功能的结果。另一方面,javascript引擎会发现此功能已被阻止等待结果,因此它将检查事件循环(例如,单击新鼠标或连接请求等)以查看是否还有其他情况它可以继续工作直到返回结果。
但是请注意,如果慢速异步功能很慢,因为它正在您的javascript代码中计算很多东西,则javascript引擎将没有很多资源来做其他事情(通过做其他事情,很可能会使慢速异步功能甚至更慢)。异步功能真正发挥作用的地方在于I / O密集型操作,例如查询数据库或传输大文件,而javascript引擎运行良好,并且真正在等待其他内容(例如数据库,文件系统等)。
以下两个代码在功能上等效:
let result = await some_slow_async_function();
和
let promise = some_slow_async_function(); // start the slow async function
// you could do other stuff here while the slow async function is running
let result = await promise; // wait for the final value from the slow async function
在上面的第二个示例中,在不使用await
关键字的情况下调用了慢速异步函数,因此它将开始执行该函数并返回一个Promise。然后,您可以做其他事情(如果有其他事情要做)。然后,await
使用该关键字进行阻止,直到承诺实际“解决”为止。因此,从for
循环的角度来看,它将同步运行。
所以:
是的,该await
关键字具有阻止正在运行的函数的作用,直到异步函数要么以值“解析”或出现错误“拒绝”为止,但它不会阻止javascript引擎,如果具有其他功能,它仍然可以执行其他操作等待中要做的事情
是的,循环的执行将是顺序的
http://javascript.info/async上有一个很棒的教程。
await
,并且在函数调用之后代码执行继续。
await
。该函数将返回,并且代码执行将继续,就像在任何函数调用之后一样。事件循环仅在调用堆栈为空时才起作用,而在await
遇到堆栈时则不起作用。顺便说一句:这个问题不是专门针对Node的,而是JavaScript。
await
)的优先级高于鼠标单击和其他代理驱动的事件。
这是我关于这个有趣问题的测试解决方案:
import crypto from "crypto";
function diyCrypto() {
return new Promise((resolve, reject) => {
crypto.pbkdf2('secret', 'salt', 2000000, 64, 'sha512', (err, res) => {
if (err) {
reject(err)
return
}
resolve(res.toString("base64"))
})
})
}
setTimeout(async () => {
console.log("before await...")
const a = await diyCrypto();
console.log("after await...", a)
}, 0);
setInterval(() => {
console.log("test....")
}, 200);
在setTimeout的回调内部,await
阻止执行。但是setInterval
保持运行状态,因此事件循环照常运行。
等待阻塞循环了吗?还是
i
等待期间继续增加?
不,等待不会阻止循环。是的,i
循环时继续增加。
是否确保do_something_with_result()的顺序是顺序的
i
?还是取决于每个函数的等待速度i
?
的顺序do_something_with_result()
是顺序保证的,但与无关i
。这取决于等待的功能运行的速度。
所有对tosome_slow_async_function()
的调用都是批量的,即如果do_something_with_result()
为a,console
那么我们将看到它打印了循环运行的次数。然后依次执行,此后,将执行所有等待调用。
为了更好地理解,您可以在下面的代码段中运行:
async function someFunction(){
for (let i=0;i<5;i++){
await callAPI();
console.log('After', i, 'th API call');
}
console.log("All API got executed");
}
function callAPI(){
setTimeout(()=>{
console.log("I was called at: "+new Date().getTime())}, 1000);
}
someFunction();
可以清楚地看到如何console.log('After', i, 'th API call');
在for循环的整个过程中首先打印行,然后在执行所有代码时结束时从中得到结果callAPI()
。
因此,如果等待后的行取决于从等待调用获得的结果,则它们将无法按预期工作。
总而言之,await
infor-loop
不能确保成功处理从await调用获得的结果,这可能需要一些时间才能完成。
在节点中,如果将一个neo-async
库与一起使用waterfall
,则可以实现这一点。
await callAPI()
立即返回。如果您更改callAPI()
以退还诺言,那么它将起作用。