>  기사  >  웹 프론트엔드  >  JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?

JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?

青灯夜游
青灯夜游앞으로
2020-11-30 18:15:524912검색

JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?

asyncawait는 사용이 비교적 간단합니다. 그러나 루프 내에서 await를 사용하려고 하면 상황이 좀 더 복잡해집니다. 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')
}

JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?

在 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”;

JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?

这种行为适用于大多数循环(比如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’

JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?

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”;

JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?

如果你在 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')
}

运行结果如下:

JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?

如果你愿意,可以在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

JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?

为什么会发生这种情况?

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

이 글에서는 if 루프에서 await를 사용할 때 주목할 만한 몇 가지 문제를 공유합니다. 🎜

예제 준비

🎜이 기사에서는 과일 바구니에서 과일 수를 얻고 싶다고 가정해 보겠습니다. 🎜
const filtered = array.filter(true);
🎜 fruitBasket에서 각 과일의 수량을 가져오려고 합니다. 과일 수를 얻으려면 getNumFruit 함수를 사용할 수 있습니다. 🎜
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')
}
🎜이제 서버에서 fruitBasket을 얻었다고 가정하고 여기서는 setTimeout을 사용하여 시뮬레이션합니다. 🎜
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')
}
🎜마지막으로 awaitgetNumFruit를 사용하여 비동기 함수에서 각 과일의 수를 가져오고 싶다고 가정해 보겠습니다. 🎜
 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를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?🎜for 루프에서 wait 사용🎜먼저 과일을 저장할 배열을 정의하세요: 🎜
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')
}
🎜이 배열을 통해 루프하세요: 🎜
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 for 루프에서 getNumFruit를 사용하여 각 과일의 수를 가져와서 콘솔에 인쇄합니다. 🎜🎜 getNumFruitpromise를 반환하므로 await를 사용하여 결과가 반환될 때까지 기다렸다가 인쇄합니다. 🎜rrreee🎜 await를 사용할 때 JavaScript가 Promise가 처리 결과를 반환할 때까지 실행을 일시 중지하려고 합니다. 이는 for 루프 내의 await가 순차적으로 실행되어야 함을 의미합니다. 🎜🎜결과는 예상한 대로입니다. 🎜rrreee🎜JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?🎜🎜 이 동작은 대부분의 루프(예: whilefor-of 루프)에서 작동합니다...🎜🎜그러나 forEach와 같이 콜백이 필요한 루프는 처리할 수 없습니다. 코드>, , 필터축소. 다음 몇 섹션에서는 awaitforEach, map 및 filter에 어떤 영향을 미치는지 살펴보겠습니다. 🎜

forEach 루프에서 wait 사용

🎜먼저 forEach를 사용하여 배열을 탐색합니다. 🎜rrreee🎜다음으로 getNumFruit를 사용하여 과일 수를 가져오겠습니다. (콜백 함수의 async 키워드에 유의하세요. 콜백 함수에 await가 있기 때문에 이 async 키워드가 필요합니다). 🎜rrreee🎜 콘솔이 다음을 인쇄할 것으로 예상했습니다. 🎜rrreee🎜 하지만 실제 결과는 다릅니다. forEach 루프에서 반환 결과를 기다리기 전에 JavaScript는 먼저 console.log('End')를 실행합니다. 🎜🎜실제 콘솔 인쇄는 다음과 같습니다. 🎜rrreee🎜 JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?🎜🎜 JavaScript의 forEach는 약속 인식을 지원하지 않으며 asyncawait도 지원하므로 이를 수행할 수 없습니다. forEach에서 사용하려면 await를 사용하세요. 🎜

지도에서 wait 사용

🎜map에서 await을 사용하는 경우 > , map은 항상 promise 배열을 반환합니다. 비동기 함수는 항상 promise를 반환하기 때문입니다. 🎜rrreee🎜JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?🎜🎜 map에서 await를 사용하면 map은 항상 promise를 반환하고 promise를 기다려야 합니다. code> 배열이 처리됩니다. 또는 await Promise.all(arrayOfPromises)를 통해 수행하세요. 🎜rrreee🎜실행 결과는 다음과 같습니다. 🎜🎜JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?🎜🎜원하시면 promise에서 반환 값을 처리할 수 있으며, 파싱된 값이 반환 값이 됩니다. 🎜rrreee

await 사용

필터 루프에서 🎜filter를 사용할 때 필터가 특정 결과 배열이 있습니다. 숫자가 20보다 큰 배열을 필터링한다고 가정해 보겠습니다. 🎜🎜대기 없이 정상적으로 filter를 사용하면 다음과 같이 됩니다. 🎜rrreee🎜Running results🎜rrreee🎜await in filter가 종료되지 않습니다. 동일한 방식으로 작동합니다. 실제로는 전혀 작동하지 않습니다. 🎜rrreee🎜JavaScript 루프에서 async/await를 사용하는 방법은 무엇입니까? 무엇에 주의해야 합니까?🎜🎜 왜 이런 일이 발생하나요? 🎜🎜 filter 콜백 내에서 await를 사용할 때 콜백은 항상 promise입니다. promise는 항상 true이므로 배열의 모든 항목은 filter를 통과합니다. await 클래스🎜를 사용하여 filter에서 다음 코드를 사용하세요.
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')
}

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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제