ホームページ > ウェブフロントエンド > jsチュートリアル > JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

青灯夜游
リリース: 2020-11-30 18:16:11
転載
4997 人が閲覧しました

JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

asyncawait と併用するのが比較的簡単です。ただし、ループ内で 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
ログイン後にコピー

最後に、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')
}
ログイン後にコピー

JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

for ループで await を使用する

最初にフルーツを格納する配列を定義します:

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”;
ログイン後にコピー

JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

この動作は、ほとんどのループ (whilefor-of ループなど) に適用されます…

ただし、forEachmapfilterreduce などのコールバックを必要とするループは処理できません。次のいくつかのセクションでは、awaitforEach、map、および filter にどのように影響するかを調べます。

forEach ループで await を使用する

まず、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’
ログイン後にコピー

JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

forEach は Promise 認識をサポートしていませんが、## もサポートしています。 #asyncawait であるため、awaitforEach で使用することはできません。

map で await を使用する

mapawait を使用すると、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”;
ログイン後にコピー

JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

mapawait を使用すると、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 _ =&gt; {   console.log('Start');   const promises = fruitsToGet.map(async fruit =&gt; {     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>実行結果は次のとおりです。

JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?必要に応じて、

promise

の戻り値を処理できます。解析された値が戻り値となります。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">const mapLoop = _ =&gt; {   // ...   const promises = fruitsToGet.map(async fruit =&gt; {     const numFruit = await getNumFruit(fruit);     return numFruit + 100   })   // ... }   “Start”; “[127, 100, 114]”; “End”;</pre><div class="contentsignin">ログイン後にコピー</div></div>

フィルター ループでの await の使用

filter

を使用するときは、特定の結果で配列をフィルター処理する必要があります。 20 を超える数の配列をフィルターするとします。 通常 (待機なしで)

filter

を使用すると、次のようになります。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">const filterLoop =  _ =&gt; {   console.log('Start')   const moreThan20 =  fruitsToGet.filter(async fruit =&gt; {     const numFruit = await fruitBasket[fruit]     return numFruit &gt; 20   })      console.log(moreThan20)    console.log('END') }</pre><div class="contentsignin">ログイン後にコピー</div></div>実行結果

Start
["apple"]
END
ログイン後にコピー

filter

await は同じようには機能しません。実際、まったく機能しません。 <div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:php;toolbar:false">const filterLoop = async _ =&gt; {   console.log('Start')   const moreThan20 =  await fruitsToGet.filter(async fruit =&gt; {     const numFruit = fruitBasket[fruit]     return numFruit &gt; 20   })      console.log(moreThan20)    console.log('END') } // 打印结果 Start [&quot;apple&quot;, &quot;grape&quot;, &quot;pear&quot;] END</pre><div class="contentsignin">ログイン後にコピー</div></div>

JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?なぜこれが起こるのですか?

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 正确的三个步骤

  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')
}
ログイン後にコピー

JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

在 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')
}
ログイン後にコピー

运行结果:

JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

当你在 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')
}
ログイン後にコピー

JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

[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')
}
ログイン後にコピー

JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

但是从上图中看到的那样,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')
}
ログイン後にコピー

1JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

这是因为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')
    }

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

1JavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?

从上面看出来什么

  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 

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

以上がJavaScript ループで async/await を使用するにはどうすればよいですか?注意が必要なことは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:segmentfault.com
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート