在JavaScript中,在循环内使用await是否会阻塞循环?

请执行以下循环:

for(var i=0; i<100; ++i){
    let result = await some_slow_async_function();
    do_something_with_result();
}
  1. do_something_with_result()是否会阻塞环路? 还是iawaiting期间继续增加?

  2. do_something_with_result()的顺序是否相对于i保证顺序? 还是取决于每个27688571217720122012的awaited函数有多快?

smorgs asked 2020-02-29T11:07:39Z
7个解决方案
48 votes
  1. 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');是否会阻塞环路? 还是在276885747986491010850ing期间继续增加i

“阻止”不是正确的词,但是,是的,我在等待时不会继续递增。 取而代之的是,执行跳回到调用276885747986491010848函数的位置,提供一个诺言作为返回值,继续执行该函数调用之后的其余代码,直到清空了代码堆栈。 然后,等待结束后,将恢复功能状态,并在该功能内继续执行。 只要该函数返回(完成),便会解决相应的诺言-早先返回的诺言。

  1. 关于276885747986491010849,是否保证顺序保证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');的顺序? 还是取决于每个276885747986491010851的awaited功能有多快?

订单得到保证。 还保证仅在调用堆栈清空后(即至少在下一个微任务可以执行之后或之后)才执行276885747986491010848之后的代码。

查看此代码段中的输出。 请特别注意它说“调用测试后”的地方:

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');

trincot answered 2020-02-29T11:08:14Z
9 votes

正如@realbart所说,它确实阻塞了循环,然后将使调用顺序化。

如果要触发大量等待的操作,然后一起处理它们,则可以执行以下操作:

const promisesToAwait = [];
for (let i = 0; i < 100; i++) {
  promisesToAwait.push(fetchDataForId(i));
}
const responses = await Promise.all(promisesToAwait);
Kris Selbekk answered 2020-02-29T11:08:39Z
8 votes

您可以在“ FOR LOOP”中测试异步/等待,如下所示:

(async  () => {
        for (let i = 0; i < 100; i++) {
                await delay();
                console.log(i);
        }
})();

function delay() {
        return new Promise((resolve, reject) => {
                setTimeout(resolve, 100);
        });
}

mzalazar answered 2020-02-29T11:09:04Z
0 votes

没有事件循环未被阻止,请参见下面的示例

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 ...')

KBH answered 2020-02-29T11:09:28Z
0 votes

await函数返回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循环的角度来看,它将同步运行。

所以:

  1. 是的,关键字await具有阻止运行函数的作用,直到异步函数“解析”一个值或“拒绝”一个错误,但是它不会阻止javascript引擎,如果有,它仍然可以执行其他操作 等待中要做的其他事情

  2. 是的,循环的执行将是顺序的

[http://javascript.info/async]上有一个很棒的教程。

Casey answered 2020-02-29T11:10:30Z
0 votes

广告1.是。 没有。

广告2.是。 没有。

证明:

async function start() 
{
  console.log('Start');

  for (var i = 0; i < 10; ++i) {
    let result = await some_slow_async_function(i);
    do_something_with_result(i);
  }
  
  console.log('Finish');
}

function some_slow_async_function(n) {
  return new Promise(res => setTimeout(()=>{
    console.log(`Job done: ${(2000/(1+n))|0} ms`);
    res(true);
  },2000/(1+n)));
}

function do_something_with_result(n) {
  console.log(`Something ${n}`);
}

start();

Kamil Kiełczewski answered 2020-02-29T11:11:02Z
-2 votes

等待阻塞循环了吗? 还是在等待期间neo-async继续增加?

不,等待不会阻止循环。 是的,neo-async在循环时继续增加。

关于2768861023447811011072,是否保证do_something_with_result()的顺序是顺序的? 还是取决于每个waterfall的等待功能有多快?

neo-async的顺序是顺序保证的,而不是neo-async的顺序,这取决于等待的功能运行的速度。

所有对neo-async的调用都被分批处理,即,如果waterfallconsole,那么我们将看到它打印了循环运行的次数。 然后依次执行,此后,将执行所有等待调用。

为了更好地理解,您可以在下面的代码段中运行:

neo-async

可以清楚地看到如何在for循环的整个过程中首先打印行neo-async,然后在执行所有代码时结束时从waterfall得到结果。

因此,如果等待之后的行取决于从等待调用获得的结果,则它们将无法按预期工作。

总而言之,waterfall中的neo-async无法确保成功处理从等待调用中获得的结果,这可能需要一些时间才能完成。

在节点中,如果将neo-async库与2768861023447811011073一起使用,则可以实现这一点。

DeeKay answered 2020-02-29T11:12:07Z
translate from https://stackoverflow.com:/questions/44410119/in-javascript-does-using-await-inside-a-loop-block-the-loop