[javascript] forEach 루프와 함께 async / await 사용


Answers

Promise.all()map() Promise.all() 과 함께 사용하는 것은 약간 이해하기 Promise.all() 장황하다.하지만 당신이 평범한 JS에서 그렇게하고 싶다면 그렇게 생각한다.

모듈을 추가하는 데 신경 쓰지 않는다면 Array 반복 방법을 구현하여 async / await에서 매우 간단한 방법으로 사용할 수 있습니다.

사례가있는 예 :

const { forEach } = require('p-iteration');
const fs = require('fs-promise');

async function printFiles () {
  const files = await getFilePaths();

  await forEach(files, async (file) => {
    const contents = await fs.readFile(file, 'utf8');
    console.log(contents);
  });
}

printFiles()

p-iteration

Question

forEach 루프에서 async/await 을 사용하는 데 문제가 있습니까? 나는 파일의 배열을 통해 반복하고 각 파일의 내용을 await 있어요.

import fs from 'fs-promise'

async function printFiles () {
  const files = await getFilePaths() // Assume this works fine

  files.forEach(async (file) => {
    const contents = await fs.readFile(file, 'utf8')
    console.log(contents)
  })
}

printFiles()

이 코드는 작동하지만이 문제가 발생할 수 있습니까? 누군가 당신에게 async/await higher를 사용하도록되어 있지 않다는 것을 말해주었습니다. 그래서 이와 같은 문제가 있는지 묻고 싶었습니다.




Array.prototype.map 과 함께 Promise.all 대신 Array.prototype.map 를 사용하여 해결 된 Promise 시작합니다.

async function printFiles () {
  const files = await getFilePaths();

  await files.reduce(async (promise, file) => {
    // This line will wait for the last async function to finish.
    // The first iteration uses an already resolved Promise
    // so, it will immediately continue.
    await promise;
    const contents = await fs.readFile(file, 'utf8')
    console.log(contents)
  }, Promise.resolve());
}



나는 잘 테스트 된 (주당 수백만 다운로드) pifyasync 모듈을 사용할 것이다. 비동기 모듈에 익숙하지 않다면 문서 를 체크 아웃 하는 것이 좋습니다. 비싼 비동기 메서드를 사용하면 코드를 단순화 할 때 여러 개발자가 메서드를 재생성하는 데 시간을 낭비하거나 악화 될 수 있으므로 비동기 코드를 유지하기가 어렵습니다.

const async = require('async')
const fs = require('fs-promise')
const pify = require('pify')

async function getFilePaths() {
    return Promise.resolve([
        './package.json',
        './package-lock.json',
    ]);
}

async function printFiles () {
  const files = await getFilePaths()

  await pify(async.eachSeries)(files, async (file) => {  // <-- run in series
  // await pify(async.each)(files, async (file) => {  // <-- run in parallel
    const contents = await fs.readFile(file, 'utf8')
    console.log(contents)
  })
  console.log('HAMBONE')
}

printFiles().then(() => {
    console.log('HAMBUNNY')
})
// ORDER OF LOGS:
// package.json contents
// package-lock.json contents
// HAMBONE
// HAMBUNNY
```




비동기 데이터를 직렬화 된 순서로 처리하고 코드에보다 일반적인 풍미를주는 파일에 몇 가지 메소드를 추가하는 것은 꽤 고통 스럽습니다. 예 :

module.exports = function () {
  var self = this;

  this.each = async (items, fn) => {
    if (items && items.length) {
      await Promise.all(
        items.map(async (item) => {
          await fn(item);
        }));
    }
  };

  this.reduce = async (items, fn, initialValue) => {
    await self.each(
      items, async (item) => {
        initialValue = await fn(initialValue, item);
      });
    return initialValue;
  };
};

이제, 그것이 ./myAsync.js에 저장되었다고 가정하면, 당신은 인접한 파일에서 아래와 비슷한 것을 할 수 있습니다 :

...
/* your server setup here */
...
var MyAsync = require('./myAsync');
var Cat = require('./models/Cat');
var Doje = require('./models/Doje');
var example = async () => {
  var myAsync = new MyAsync();
  var doje = await Doje.findOne({ name: 'Doje', noises: [] }).save();
  var cleanParams = [];

  // FOR EACH EXAMPLE
  await myAsync.each(['bork', 'concern', 'heck'], 
    async (elem) => {
      if (elem !== 'heck') {
        await doje.update({ $push: { 'noises': elem }});
      }
    });

  var cat = await Cat.findOne({ name: 'Nyan' });

  // REDUCE EXAMPLE
  var friendsOfNyanCat = await myAsync.reduce(cat.friends,
    async (catArray, friendId) => {
      var friend = await Friend.findById(friendId);
      if (friend.name !== 'Long cat') {
        catArray.push(friend.name);
      }
    }, []);
  // Assuming Long Cat was a friend of Nyan Cat...
  assert(friendsOfNyanCat.length === (cat.friends.length - 1));
}



중요한 주의 사항 은 다음과 같습니다. await + for .. of 메소드와 forEach + async way는 실제로 다른 효과를 나타냅니다.

실제 for 루프를 기다리면 모든 비동기 호출이 하나씩 실행되는지 확인할 수 있습니다. 그리고 forEach + async 방법은 동시에 모든 약속을 해고합니다. DB 질의를하거나 볼륨 제한이있는 웹 서비스를 방문 하고 한 번에 100,000 건의 전화를 끊지 않으려는 경우 에는 더 빠르지 만 때때로 압도 됩니다 .

async/await 사용하지 않고 파일이 차례로 읽히는 지 확인하려면 reduce + promise (덜 우아함)를 사용할 수도 있습니다.

files.reduce((lastPromise, file) => 
 lastPromise.then(() => 
   fs.readFile(file, 'utf8')
 ), Promise.resolve()
)

또는 forEachAsync를 만들어 루프를 만들 때 기본적으로 사용할 수 있습니다.

Array.prototype.forEachAsync = async function(cb){
    for(let x of this){
        await cb(x);
    }
}





Links