async
は await
と併用するのが比較的簡単です。ただし、ループ内で await
を使用しようとすると、状況が少し複雑になります。
この記事では、if ループで 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
最後に、await
と getNumFruit
を使用して、非同期関数で各フルーツの数を取得するとします。
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') }
最初にフルーツを格納する配列を定義します:
const fruitsToGet = [“apple”, “grape”, “pear”];
Loopこの配列をトラバースします。
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> を使用する場合、Promise が処理結果を返すまで JavaScript の実行を一時停止したいとします。これは、<code>for</code> ループ内の <code>await</code> が順番に実行される必要があることを意味します。 </p><p>結果はご想像どおりです。 </p><pre class="brush:php;toolbar:false">“Start”; “Apple: 27”; “Grape: 0”; “Pear: 14”; “End”;
この動作は、ほとんどのループ (while
や for-of
ループなど) に適用されます…
ただし、forEach
、map
、filter
、reduce
などのコールバックを必要とするループは処理できません。次のいくつかのセクションでは、await
が forEach
、map、および filter
にどのように影響するかを調べます。
まず、forEach
を使用して配列を走査します。
const forEach = _ => { console.log('start'); fruitsToGet.forEach(fruit => { //... }) console.log('End') }
次に、getNumFruit
を使用してフルーツの数を取得してみます。 (コールバック関数内の async
キーワードに注意してください。コールバック関数内に await
があるため、この async
キーワードが必要です)。
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
ループで返される結果を待つ前に、JavaScript はまず console.log('End') を実行します。
実際のコンソール出力は次のとおりです: JavaScript の
‘Start’ ‘End’ ‘27’ ‘0’ ‘14’
forEach
は Promise 認識をサポートしていませんが、## もサポートしています。 #async と
await であるため、
await を
forEach で使用することはできません。
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”;
map で
await を使用すると、
map は常に
promises ## を返します#、promises
配列が処理されるまで待つ必要があります。または、await Promise.all(arrayOfPromises)
を介してこれを実行します。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">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')
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
実行結果は次のとおりです。
必要に応じて、
promise の戻り値を処理できます。解析された値が戻り値となります。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">const mapLoop = _ => {
// ...
const promises = fruitsToGet.map(async fruit => {
const numFruit = await getNumFruit(fruit);
return numFruit + 100
})
// ...
}
“Start”;
“[127, 100, 114]”;
“End”;</pre><div class="contentsignin">ログイン後にコピー</div></div>
を使用するときは、特定の結果で配列をフィルター処理する必要があります。 20 を超える数の配列をフィルターするとします。 通常 (待機なしで)
を使用すると、次のようになります。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">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')
}</pre><div class="contentsignin">ログイン後にコピー</div></div>
実行結果
Start ["apple"] END
await
は同じようには機能しません。実際、まったく機能しません。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">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</pre><div class="contentsignin">ログイン後にコピー</div></div>
なぜこれが起こるのですか?
filter コールバックで await
を使用する場合、コールバックは次のようになります。常に約束
。 promise
は常に true であるため、配列内のすべての項目は filter
を通過します。 filter
await
class で次のコードを使用します。<div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">const filtered = array.filter(true);</pre><div class="contentsignin">ログイン後にコピー</div></div>
<p>在<code>filter
使用 await
正确的三个步骤
map
返回一个promise 数组await
等待处理结果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') }
如果想要计算 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') }
运行结果:
当你在 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') }
[object Promise]14
是什么 鬼??
剖析这一点很有趣。
sum
为0
。numFruit
是27
(通过getNumFruit(apple)
的得到的值),0 + 27 = 27
。sum
是一个promise
。 (为什么?因为异步函数总是返回promises
!)numFruit
是0
.promise 无法正常添加到对象,因此JavaScript将其转换为[object Promise]
字符串。 [object Promise] + 0
是object Promise] 0
。sum
也是一个promise
。 numFruit
是14
. [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') }
但是从上图中看到的那样,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') }
这是因为reduce
可以在等待循环的下一个迭代之前触发所有三个getNumFruit
promise。然而,这个方法有点令人困惑,因为你必须注意等待的顺序。
在reduce中使用wait最简单(也是最有效)的方法是
map
返回一个promise 数组await
等待处理结果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')
}
这个版本易于阅读和理解,需要一秒钟来计算水果总数。
await
调用,请使用for
循环(或任何没有回调的循环)。forEach
一起使用await
,而是使用for
循环(或任何没有回调的循环)。filter
和 reduce
中使用 await
,如果需要,先用 map
进一步骤处理,然后在使用 filter
和 reduce
进行处理。原文地址:https://medium.com/free-code-camp/javascript-async-and-await-in-loops-30ecc5fb3939
更多编程相关知识,请访问:编程学习网站!!
以上がJavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。