Heim  >  Artikel  >  Web-Frontend  >  Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

青灯夜游
青灯夜游nach vorne
2020-11-30 18:15:524912Durchsuche

Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

async und await sind relativ einfach zu verwenden. Etwas komplizierter wird es jedoch, wenn Sie versuchen, await innerhalb einer Schleife zu verwenden. asyncawait 的使用方式相对简单。 但当你尝试在循环中使用await时,事情就会变得复杂一些。

在本文中,分享一些在如果循环中使用await值得注意的问题。

准备一个例子

对于这篇文章,假设你想从水果篮中获取水果的数量。

const fruitBasket = {
 apple: 27,
 grape: 0,
 pear: 14
};

你想从fruitBasket获得每个水果的数量。 要获取水果的数量,可以使用getNumFruit函数。

const getNumFruit = fruit => {
  return fruitBasket[fruit];
};

const numApples = getNumFruit('apple');
console.log(numApples); //27

现在,假设fruitBasket是从服务器上获取,这里我们使用 setTimeout 来模拟。

const sleep = ms => {
  return new Promise(resolve => setTimeout(resolve, ms))
};

const getNumFruie = fruit => {
  return sleep(1000).then(v => fruitBasket[fruit]);
};

getNumFruit("apple").then(num => console.log(num)); // 27

最后,假设你想使用awaitgetNumFruit来获取异步函数中每个水果的数量。

const control = async _ => {
  console.log('Start')

  const numApples = await getNumFruit('apple');
  console.log(numApples);

  const numGrapes = await getNumFruit('grape');
  console.log(numGrapes);

  const numPears = await getNumFruit('pear');
  console.log(numPears);

  console.log('End')
}

Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

在 for 循环中使用 await

首先定义一个存放水果的数组:

const fruitsToGet = [“apple”, “grape”, “pear”];

循环遍历这个数组:

const forLoop = async _ => {
  console.log('Start');
  
  for (let index = 0; index <p>在<code>for</code>循环中,过上使用<code>getNumFruit</code>来获取每个水果的数量,并将数量打印到控制台。</p><p>由于<code>getNumFruit</code>返回一个<code>promise</code>,我们使用 <code>await</code> 来等待结果的返回并打印它。</p><pre class="brush:php;toolbar:false">const forLoop = async _ => {
  console.log('start');

  for (let index = 0; index <p>当使用<code>await</code>时,希望JavaScript暂停执行,直到等待 promise 返回处理结果。这意味着<code>for</code>循环中的<code>await</code> 应该按顺序执行。</p><p>结果正如你所预料的那样。</p><pre class="brush:php;toolbar:false">“Start”;
“Apple: 27”;
“Grape: 0”;
“Pear: 14”;
“End”;

Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

这种行为适用于大多数循环(比如whilefor-of循环)…

但是它不能处理需要回调的循环,如forEachmapfilterreduce。在接下来的几节中,我们将研究await 如何影响forEach、map和filter

在 forEach 循环中使用 await

首先,使用 forEach 对数组进行遍历。

const forEach = _ => {
  console.log('start');

  fruitsToGet.forEach(fruit => {
    //...
  })

  console.log('End')
}

接下来,我们将尝试使用getNumFruit获取水果数量。 (注意回调函数中的async关键字。我们需要这个async关键字,因为await在回调函数中)。

const forEachLoop = _ => {
  console.log('Start');

  fruitsToGet.forEach(async fruit => {
    const numFruit = await getNumFruit(fruit);
    console.log(numFruit)
  });

  console.log('End')
}

我期望控制台打印以下内容:

“Start”;
“27”;
“0”;
“14”;
“End”;

但实际结果是不同的。在forEach循环中等待返回结果之前,JavaScrip先执行了 console.log('End')。

实际控制台打印如下:

‘Start’
‘End’
‘27’
‘0’
‘14’

Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

JavaScript 中的 forEach不支持 promise 感知,也支持 asyncawait,所以不能在 forEach 使用 await

在 map 中使用 await

如果在map中使用await, map 始终返回promise数组,这是因为异步函数总是返回promise

const mapLoop = async _ => {
  console.log('Start')
  const numFruits = await fruitsToGet.map(async fruit => {
    const numFruit = await getNumFruit(fruit);
    return numFruit;
  })
  
  console.log(numFruits);

  console.log('End')
}
      

“Start”;
“[Promise, Promise, Promise]”;
“End”;

Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

如果你在 map 中使用 awaitmap 总是返回promises,你必须等待promises 数组得到处理。 或者通过await Promise.all(arrayOfPromises)来完成此操作。

const mapLoop = async _ => {
  console.log('Start');

  const promises = fruitsToGet.map(async fruit => {
    const numFruit = await getNumFruit(fruit);
    return numFruit;
  });

  const numFruits = await Promise.all(promises);
  console.log(numFruits);

  console.log('End')
}

运行结果如下:

Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

如果你愿意,可以在promise 中处理返回值,解析后的将是返回的值。

const mapLoop = _ => {
  // ...
  const promises = fruitsToGet.map(async fruit => {
    const numFruit = await getNumFruit(fruit);
    return numFruit + 100
  })
  // ...
}
 
“Start”;
“[127, 100, 114]”;
“End”;

在 filter 循环中使用 await

当你使用filter时,希望筛选具有特定结果的数组。假设过滤数量大于20的数组。

如果你正常使用filter (没有 await),如下:

const filterLoop =  _ => {
  console.log('Start')

  const moreThan20 =  fruitsToGet.filter(async fruit => {
    const numFruit = await fruitBasket[fruit]
    return numFruit > 20
  })
  
  console.log(moreThan20) 
  console.log('END')
}

运行结果

Start
["apple"]
END

filter 中的await不会以相同的方式工作。 事实上,它根本不起作用。

const filterLoop = async _ => {
  console.log('Start')

  const moreThan20 =  await fruitsToGet.filter(async fruit => {
    const numFruit = fruitBasket[fruit]
    return numFruit > 20
  })
  
  console.log(moreThan20) 
  console.log('END')
}


// 打印结果
Start
["apple", "grape", "pear"]
END

Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

为什么会发生这种情况?

当在filter 回调中使用await时,回调总是一个promise。由于promise 总是真的,数组中的所有项都通过filter 。在filter 使用 await

In diesem Artikel besprechen wir einige beachtenswerte Probleme bei der Verwendung von await in if-Schleifen. 🎜

Bereiten Sie ein Beispiel vor

🎜Angenommen, Sie möchten für diesen Artikel die Anzahl der Früchte aus einem Obstkorb ermitteln. 🎜
const filtered = array.filter(true);
🎜Sie möchten die Menge jeder Frucht aus fruitBasket erhalten. Um die Anzahl der Früchte zu ermitteln, können Sie die Funktion getNumFruit verwenden. 🎜
const filterLoop = async _ => {
  console.log('Start');

  const promises = await fruitsToGet.map(fruit => getNumFruit(fruit));
 
  const numFruits = await Promise.all(promises);

  const moreThan20 = fruitsToGet.filter((fruit, index) => {
    const numFruit = numFruits[index];
    return numFruit > 20;
  })

  console.log(moreThan20);
  console.log('End')
}
🎜Angenommen, dass fruitBasket vom Server abgerufen wird, verwenden wir hier setTimeout zur Simulation. 🎜
const reduceLoop = _ => {
  console.log('Start');

  const sum = fruitsToGet.reduce((sum, fruit) => {
    const numFruit = fruitBasket[fruit];
    return sum + numFruit;
  }, 0)

  console.log(sum)
  console.log('End')
}
🎜Abschließend nehmen wir an, Sie möchten await und getNumFruit verwenden, um die Anzahl jeder Frucht in einer asynchronen Funktion abzurufen. 🎜
 const reduceLoop = async _ => {
  console.log('Start');

  const sum = await fruitsToGet.reduce(async (sum, fruit) => {
    const numFruit = await fruitBasket[fruit];
    return sum + numFruit;
  }, 0)

  console.log(sum)
  console.log('End')
}
🎜Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?🎜Verwenden Sie „await“ in einer for-Schleife🎜Definieren Sie zunächst ein Array zum Speichern von Früchten: 🎜
const reduceLoop = async _ => {
  console.log('Start');

  const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => {
    const sum = await promisedSum;
    const numFruit = await fruitBasket[fruit];
    return sum + numFruit;
  }, 0)

  console.log(sum)
  console.log('End')
}
🎜Durchlaufen Sie dieses Array: 🎜
const reduceLoop = async _ => {
  console.log('Start');

  const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => {
    const numFruit = await fruitBasket[fruit];
    const sum = await promisedSum;
    return sum + numFruit;
  }, 0)

  console.log(sum)
  console.log('End')
}
🎜In Verwenden Sie in der for-Schleife getNumFruit, um die Nummer jeder Frucht abzurufen und die Nummer auf der Konsole auszugeben. 🎜🎜Da getNumFruit ein promise zurückgibt, verwenden wir await, um auf die Rückgabe des Ergebnisses zu warten und es auszudrucken. 🎜rrreee🎜Wenn Sie await verwenden, soll JavaScript die Ausführung anhalten, bis es auf das Versprechen wartet, das Verarbeitungsergebnis zurückzugeben. Das bedeutet, dass await in einer for-Schleife nacheinander ausgeführt werden sollte. 🎜🎜Die Ergebnisse sind wie erwartet. 🎜rrreee🎜Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?🎜🎜 Dieses Verhalten funktioniert für die meisten Schleifen (z. B. while- und for-of-Schleifen) ... 🎜🎜Es kann jedoch keine Schleifen verarbeiten, die Rückrufe erfordern, z. B. forEach code>, map, filter und reduce. In den nächsten Abschnitten werden wir untersuchen, wie sich await auf forEach, Map und filter auswirkt. 🎜

Verwenden Sie „await“

in der forEach-Schleife. 🎜Verwenden Sie zunächst forEach, um das Array zu durchlaufen. 🎜rrreee🎜Als nächstes werden wir versuchen, mit getNumFruit die Anzahl der Früchte zu ermitteln. (Beachten Sie das Schlüsselwort async in der Rückruffunktion. Wir benötigen dieses Schlüsselwort async, da await in der Rückruffunktion enthalten ist.) 🎜rrreee🎜 Ich habe erwartet, dass die Konsole Folgendes ausgibt: 🎜rrreee🎜, aber das tatsächliche Ergebnis ist anders. Bevor in der forEach-Schleife auf das Rückgabeergebnis gewartet wird, führt JavaScript zunächst console.log('End') aus. 🎜🎜Der eigentliche Konsolendruck lautet wie folgt: 🎜rrreee🎜 Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?🎜🎜forEach in JavaScript unterstützt kein Promise Awareness. Es unterstützt auch async und await, also nicht in forEach verwendet werden, verwendet await. 🎜

Await in der Karte verwenden

🎜Wenn Sie awaitin map > verwenden , map gibt immer ein promise-Array zurück, da asynchrone Funktionen immer promise zurückgeben. 🎜rrreee🎜Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?🎜🎜 Wenn Sie await in map verwenden, gibt map immer promises zurück und Sie müssen auf promises warten. Code> Array wird verarbeitet. Oder tun Sie dies über await Promise.all(arrayOfPromises). 🎜rrreee🎜Die laufenden Ergebnisse sind wie folgt: 🎜🎜5. gif🎜🎜Wenn Sie möchten, können Sie den Rückgabewert in promise verarbeiten, und der analysierte Wert wird der zurückgegebene Wert sein. 🎜rrreee

Verwenden Sie „await“

in der Filterschleife. 🎜Wenn Sie filter verwenden, möchten Sie, dass der Filter dies tut haben ein bestimmtes Array von Ergebnissen. Angenommen, Sie filtern ein Array, dessen Anzahl größer als 20 ist. 🎜🎜Wenn Sie filter normal (ohne Warten) verwenden, gilt Folgendes: 🎜rrreee🎜Laufende Ergebnisse🎜rrreee🎜await in filter wird nicht beendet mit Funktioniert genauso. Tatsächlich funktioniert es überhaupt nicht. 🎜rrreee🎜Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?🎜🎜 Warum passiert das? 🎜🎜Wenn await innerhalb eines filter-Rückrufs verwendet wird, ist der Rückruf immer ein promise. Da promise immer wahr ist, durchlaufen alle Elemente im Array den filter. Verwenden Sie den folgenden Code in filter unter Verwendung der Klasse await🎜
const filtered = array.filter(true);

filter使用 await 正确的三个步骤

  1. 使用map返回一个promise 数组
  2. 使用 await 等待处理结果
  3. 使用 filter 对返回的结果进行处理
const filterLoop = async _ => {
  console.log('Start');

  const promises = await fruitsToGet.map(fruit => getNumFruit(fruit));
 
  const numFruits = await Promise.all(promises);

  const moreThan20 = fruitsToGet.filter((fruit, index) => {
    const numFruit = numFruits[index];
    return numFruit > 20;
  })

  console.log(moreThan20);
  console.log('End')
}

Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

在 reduce 循环中使用 await

如果想要计算 fruitBastet中的水果总数。 通常,你可以使用reduce循环遍历数组并将数字相加。

const reduceLoop = _ => {
  console.log('Start');

  const sum = fruitsToGet.reduce((sum, fruit) => {
    const numFruit = fruitBasket[fruit];
    return sum + numFruit;
  }, 0)

  console.log(sum)
  console.log('End')
}

运行结果:

Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

当你在 reduce 中使用await时,结果会变得非常混乱。

 const reduceLoop = async _ => {
  console.log('Start');

  const sum = await fruitsToGet.reduce(async (sum, fruit) => {
    const numFruit = await fruitBasket[fruit];
    return sum + numFruit;
  }, 0)

  console.log(sum)
  console.log('End')
}

Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

[object Promise]14 是什么 鬼??

剖析这一点很有趣。

  1. 在第一次遍历中,sum0numFruit27(通过getNumFruit(apple)的得到的值),0 + 27 = 27
  2. 在第二次遍历中,sum是一个promise。 (为什么?因为异步函数总是返回promises!)numFruit0.promise 无法正常添加到对象,因此JavaScript将其转换为[object Promise]字符串。 [object Promise] + 0object Promise] 0
  3. 在第三次遍历中,sum 也是一个promisenumFruit14. [object Promise] + 14[object Promise] 14

解开谜团!

这意味着,你可以在reduce回调中使用await,但是你必须记住先等待累加器!

const reduceLoop = async _ => {
  console.log('Start');

  const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => {
    const sum = await promisedSum;
    const numFruit = await fruitBasket[fruit];
    return sum + numFruit;
  }, 0)

  console.log(sum)
  console.log('End')
}

Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

但是从上图中看到的那样,await 操作都需要很长时间。 发生这种情况是因为reduceLoop需要等待每次遍历完成promisedSum

有一种方法可以加速reduce循环,如果你在等待promisedSum之前先等待getNumFruits(),那么reduceLoop只需要一秒钟即可完成:

const reduceLoop = async _ => {
  console.log('Start');

  const sum = await fruitsToGet.reduce(async (promisedSum, fruit) => {
    const numFruit = await fruitBasket[fruit];
    const sum = await promisedSum;
    return sum + numFruit;
  }, 0)

  console.log(sum)
  console.log('End')
}

1Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

这是因为reduce可以在等待循环的下一个迭代之前触发所有三个getNumFruit promise。然而,这个方法有点令人困惑,因为你必须注意等待的顺序。

在reduce中使用wait最简单(也是最有效)的方法是

  1. 使用map返回一个promise 数组
  2. 使用 await 等待处理结果
  3. 使用 reduce 对返回的结果进行处理

    const reduceLoop = async _ => {
     console.log('Start');

    const promises = fruitsToGet.map(getNumFruit);
     const numFruits = await Promise.all(promises);
     const sum = numFruits.reduce((sum, fruit) => sum + fruit);

    console.log(sum)
     console.log('End')
    }

这个版本易于阅读和理解,需要一秒钟来计算水果总数。

1Wie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?

从上面看出来什么

  1. 如果你想连续执行await调用,请使用for循环(或任何没有回调的循环)。
  2. 永远不要和forEach一起使用await,而是使用for循环(或任何没有回调的循环)。
  3. 不要在 filterreduce 中使用 await,如果需要,先用 map 进一步骤处理,然后在使用 filterreduce 进行处理。

原文地址:https://medium.com/free-code-camp/javascript-async-and-await-in-loops-30ecc5fb3939 

更多编程相关知识,请访问:编程学习网站!!

Das obige ist der detaillierte Inhalt vonWie verwende ich async/await in JavaScript-Schleifen? Worauf sollte ich achten?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen