forEachループでasync / awaitを使用する

1405
Saad 2016-06-02 08:55.

async/awaitforEachループで使用することに問題はありますか?ファイルの配列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私はこれですべての問題があった場合、お聞きしたかったので、このような高階関数に。

19 answers

2680
Bergi 2016-06-02 09:02.

確かにコードは機能しますが、期待どおりに機能しないことは間違いありません。複数の非同期呼び出しを起動するだけですが、printFiles関数はその後すぐに戻ります。

順番に読む

ファイルを順番に読みたい場合は、実際には使用できませんforEachfor … of代わりに最新のループを使用してください。await期待どおりに機能します。

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

  for (const file of files) {
    const contents = await fs.readFile(file, 'utf8');
    console.log(contents);
  }
}

並行して読む

ファイルを並行して読み取りたい場合は、実際には使用できませんforEachasyncコールバック関数呼び出しのそれぞれはpromiseを返しますが、あなたはそれらを待つのではなく捨てています。map代わりに使用するだけで、次のような一連の約束を待つことができますPromise.all

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

  await Promise.all(files.map(async (file) => {
    const contents = await fs.readFile(file, 'utf8')
    console.log(contents)
  }));
}
274
Francisco Mateo 2018-06-16 01:17.

ES2018を使用すると、上記のすべての回答を大幅に簡素化できます。

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

  for await (const contents of fs.readFile(file, 'utf8')) {
    console.log(contents)
  }
}

仕様を参照してください:proposal-async-iteration


2018-09-10:この回答は最近大きな注目を集めています。非同期反復の詳細については、Axel Rauschmayerのブログ投稿を参照してください:ES2018:非同期反復

81
Timothy Zorn 2018-03-27 09:48.

(sが解決される順序を保証するものではありません)Promise.allと組み合わせて使用​​する代わりに、解決済み:から始めて使用します。Array.prototype.mapPromiseArray.prototype.reducePromise

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());
}
35
Antonio Val 2017-07-10 22:15.

npmのp-iterationモジュールは、配列反復法を実装しているため、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);
  });
})();
32
Matt 2018-03-23 05:11.

ここにいくつかのforEachAsyncプロトタイプがあります。あなたがawaitそれらに必要であることに注意してください:

Array.prototype.forEachAsync = async function (fn) {
    for (let t of this) { await fn(t) }
}

Array.prototype.forEachAsyncParallel = async function (fn) {
    await Promise.all(this.map(fn));
}

注意あなたがあなた自身のコードでこれを含むことが、あなたは(彼らのグローバルを汚染を避けるために)あなたが他の人に配布するライブラリでこれを含めるべきではありません。

9
chharvey 2018-02-23 14:47.

@Bergiの回答に加えて、3番目の選択肢を提供したいと思います。これは@Bergiの2番目の例と非常に似ていますreadFileが、それぞれを個別に待機する代わりに、最後に待機するpromiseの配列を作成します。

import fs from 'fs-promise';
async function printFiles () {
  const files = await getFilePaths();

  const promises = files.map((file) => fs.readFile(file, 'utf8'))

  const contents = await Promise.all(promises)

  contents.forEach(console.log);
}

とにかくPromiseオブジェクトを返す.map()のでasync、渡される関数はである必要はないことに注意してくださいfs.readFile。したがってpromises、に送信できるPromiseオブジェクトの配列ですPromise.all()

@Bergiの回答では、コンソールはファイルの内容を読み取った順序でログに記録する場合があります。たとえば、非常に小さなファイルが非常に大きなファイルの前に読み取りを終了した場合、配列内の大きなファイルの後に小さなファイルがあったとしても、最初にログに記録されますfiles。ただし、上記の私の方法では、コンソールが提供された配列と同じ順序でファイルをログに記録することが保証されています。

7
master_dodo 2019-05-27 12:08.

fs約束に基づく場合、Bergiのソリューションはうまく機能します。bluebirdfs-extraまたはfs-promiseを使用できます。

ただし、ノードのネイティブfsライブラリの解決策は次のとおりです。

const result = await Promise.all(filePaths
    .map( async filePath => {
      const fileContents = await getAssetFromCache(filePath, async function() {

        // 1. Wrap with Promise    
        // 2. Return the result of the Promise
        return await new Promise((res, rej) => {
          fs.readFile(filePath, 'utf8', function(err, data) {
            if (data) {
              res(data);
            }
          });
        });
      });

      return fileContents;
    }));

注: require('fs')強制的に3番目の引数として関数を取ります。それ以外の場合は、エラーをスローします。

TypeError [ERR_INVALID_CALLBACK]: Callback must be a function
6
Hooman Askari 2017-08-27 00:47.

上記の両方のソリューションは機能しますが、Antonio'sはより少ないコードで仕事をします。これが、データベースから、いくつかの異なる子参照からのデータを解決し、それらをすべて配列にプッシュして、結局のところ約束で解決するのにどのように役立ったかです。完了:

Promise.all(PacksList.map((pack)=>{
    return fireBaseRef.child(pack.folderPath).once('value',(snap)=>{
        snap.forEach( childSnap => {
            const file = childSnap.val()
            file.id = childSnap.key;
            allItems.push( file )
        })
    })
})).then(()=>store.dispatch( actions.allMockupItems(allItems)))
5
Jay Edwards 2017-09-23 13:03.

非同期データをシリアル化された順序で処理し、コードに従来のフレーバーを与えるファイルにいくつかのメソッドをポップするのは非常に簡単です。例えば:

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));
}
5
Oliver Dixon 2020-04-17 07:18.

このソリューションはメモリも最適化されているため、10,000のデータアイテムとリクエストで実行できます。ここにある他の解決策のいくつかは、大きなデータセットでサーバーをクラッシュさせます。

TypeScriptの場合:

export async function asyncForEach<T>(array: Array<T>, callback: (item: T, index: number) => void) {
        for (let index = 0; index < array.length; index++) {
            await callback(array[index], index);
        }
    }

使い方?

await asyncForEach(receipts, async (eachItem) => {
    await ...
})
4
LeOn - Han Li 2017-09-25 10:00.

重要な注意点の1つは、await + for .. of方法とforEach + async方法が実際には異なる効果をもたらすことです。

持つawait本当の内側にforループすることを確認します、すべての非同期呼び出しが1つずつ実行します。そして、このforEach + async方法はすべてのプロミスを同時に実行します。これは高速ですが、場合によっては圧倒されます(DBクエリを実行したり、ボリューム制限のあるWebサービスにアクセスしたりして、一度に100,000回の呼び出しを実行したくない場合)。

使用reduce + promiseせずasync/await、ファイルが次々に読み取られるようにしたい場合は、(あまりエレガントではない)を使用することもできます。

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

または、forEachAsyncを作成して支援することもできますが、基本的には同じforループの基礎を使用します。

Array.prototype.forEachAsync = async function(cb){
    for(let x of this){
        await cb(x);
    }
}
4
gsaandy 2019-12-02 06:59.

元の答えに追加するだけ

  • 元の回答の並列読み取り構文は、混乱して読みにくい場合があります。別のアプローチで記述できる場合もあります。
async function printFiles() {
  const files = await getFilePaths();
  const fileReadPromises = [];

  const readAndLogFile = async filePath => {
    const contents = await fs.readFile(file, "utf8");
    console.log(contents);
    return contents;
  };

  files.forEach(file => {
    fileReadPromises.push(readAndLogFile(file));
  });

  await Promise.all(fileReadPromises);
}

  • 順次操作の場合、for ... ofだけでなく、通常のforループも機能します
async function printFiles() {
  const files = await getFilePaths();

  for (let i = 0; i < files.length; i++) {
    const file = files[i];
    const contents = await fs.readFile(file, "utf8");
    console.log(contents);
  }
}

4
lukaswilkeer 2019-12-21 15:11.

@Bergiの応答と同様ですが、1つの違いがあります。

Promise.all 1つが拒否された場合、すべての約束を拒否します。

したがって、再帰を使用します。

const readFilesQueue = async (files, index = 0) {
    const contents = await fs.readFile(files[index], 'utf8')
    console.log(contents)

    return files.length <= index
        ? readFilesQueue(files, ++index)
        : files

}

const printFiles async = () => {
    const files = await getFilePaths();
    const printContents = await readFilesQueue(files)

    return printContents
}

printFiles()

PS

readFilesQueueprintFilesによって導入された副作用*の原因の外にあるので、console.logモック、テスト、またはスパイする方が良いので、コンテンツを返す関数(補足)があるのはクールではありません。

したがって、コードは次のように簡単に設計できます。「純粋」**で副作用が発生しない3つの別個の関数は、リスト全体を処理し、失敗したケースを処理するように簡単に変更できます。

const files = await getFilesPath()

const printFile = async (file) => {
    const content = await fs.readFile(file, 'utf8')
    console.log(content)
}

const readFiles = async = (files, index = 0) => {
    await printFile(files[index])

    return files.lengh <= index
        ? readFiles(files, ++index)
        : files
}

readFiles(files)

将来の編集/現在の状態

Nodeはトップレベルの待機をサポートします(これはまだプラグインを持っていません、持っていません、そしてハーモニーフラグを介して有効にすることができます)、それはクールですが1つの問題を解決しません(戦略的に私はLTSバージョンでのみ動作します)。ファイルを取得する方法は?

合成を使用します。コードを考えると、これはモジュール内にあるという感覚を私に引き起こします。したがって、それを実行する関数が必要です。そうでない場合は、IIFEを使用して、役割コードを非同期関数にラップし、すべてを実行する単純なモジュールを作成する必要があります。そうしないと、正しい方法で構成を行うことができます。

// more complex version with IIFE to a single module
(async (files) => readFiles(await files())(getFilesPath)

セマンティクスにより、変数の名前が変わることに注意してください。ファンクター(別の関数から呼び出すことができる関数)を渡し、アプリケーションのロジックの初期ブロックを含むメモリー上のポインターを受け取ります。

しかし、モジュールではなく、ロジックをエクスポートする必要がある場合はどうでしょうか。

関数を非同期関数でラップします。

export const readFilesQueue = async () => {
    // ... to code goes here
}

または、変数の名前を変更します...


* 副作用によって、IOのように、アプリケーションの状態/動作を変更したり、アプリケーションにバグを導入したりする可能性のある、アプリケーションの共食い効果を意味します。

** 「純粋」とは、関数が純粋ではなく、コードが純粋なバージョンに収束できるため、アポストロフィになります。コンソール出力がなく、データ操作のみです。

これとは別に、純粋にするために、エラーが発生しやすい副作用を処理し、そのエラーをアプリケーションとは別に処理するモナドを操作する必要があります。

3
Babakness 2018-02-28 18:41.

タスク、未来化、およびトラバース可能なリストを使用して、簡単に行うことができます

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

  List(files).traverse( Task.of, f => readFile( f, 'utf-8'))
    .fork( console.error, console.log)
}

これを設定する方法は次のとおりです

import fs from 'fs';
import { futurize } from 'futurize';
import Task from 'data.task';
import { List } from 'immutable-ext';

const future = futurizeP(Task)
const readFile = future(fs.readFile)

目的のコードを構造化する別の方法は、

const printFiles = files => 
  List(files).traverse( Task.of, fn => readFile( fn, 'utf-8'))
    .fork( console.error, console.log)

または、おそらくさらに機能指向

// 90% of encodings are utf-8, making that use case super easy is prudent

// handy-library.js
export const readFile = f =>
  future(fs.readFile)( f, 'utf-8' )

export const arrayToTaskList = list => taskFn => 
  List(files).traverse( Task.of, taskFn ) 

export const readFiles = files =>
  arrayToTaskList( files, readFile )

export const printFiles = files => 
  readFiles(files).fork( console.error, console.log)

次に、親関数から

async function main() {
  /* awesome code with side-effects before */
  printFiles( await getFiles() );
  /* awesome code with side-effects after */
}

エンコーディングの柔軟性を本当に高めたい場合は、これを行うことができます(楽しみのために、提案されたパイプフォワード演算子を使用しています

import { curry, flip } from 'ramda'

export const readFile = fs.readFile 
  |> future,
  |> curry,
  |> flip

export const readFileUtf8 = readFile('utf-8')

PS-私はコンソールでこのコードを試していませんでした、いくつかのタイプミスがあるかもしれません...「まっすぐなフリースタイル、ドームの上から!」90年代の子供たちが言うように。:-p

3
Beau 2019-03-13 13:31.

現在、Array.forEachプロトタイププロパティは非同期操作をサポートしていませんが、ニーズに合わせて独自のポリフィルを作成できます。

// Example of asyncForEach Array poly-fill for NodeJs
// file: asyncForEach.js
// Define asynForEach function 
async function asyncForEach(iteratorFunction){
  let indexer = 0
  for(let data of this){
    await iteratorFunction(data, indexer)
    indexer++
  }
}
// Append it as an Array prototype property
Array.prototype.asyncForEach = asyncForEach
module.exports = {Array}

以上です!これで、これらの操作の後に定義されたすべての配列で使用可能な非同期forEachメソッドができました。

テストしてみましょう...

// Nodejs style
// file: someOtherFile.js

const readline = require('readline')
Array = require('./asyncForEach').Array
const log = console.log

// Create a stream interface
function createReader(options={prompt: '>'}){
  return readline.createInterface({
    input: process.stdin
    ,output: process.stdout
    ,prompt: options.prompt !== undefined ? options.prompt : '>'
  })
}
// Create a cli stream reader
async function getUserIn(question, options={prompt:'>'}){
  log(question)
  let reader = createReader(options)
  return new Promise((res)=>{
    reader.on('line', (answer)=>{
      process.stdout.cursorTo(0, 0)
      process.stdout.clearScreenDown()
      reader.close()
      res(answer)
    })
  })
}

let questions = [
  `What's your name`
  ,`What's your favorite programming language`
  ,`What's your favorite async function`
]
let responses = {}

async function getResponses(){
// Notice we have to prepend await before calling the async Array function
// in order for it to function as expected
  await questions.asyncForEach(async function(question, index){
    let answer = await getUserIn(question)
    responses[question] = answer
  })
}

async function main(){
  await getResponses()
  log(responses)
}
main()
// Should prompt user for an answer to each question and then 
// log each question and answer as an object to the terminal

mapのような他の配列関数のいくつかについても同じことができます...

async function asyncMap(iteratorFunction){
  let newMap = []
  let indexer = 0
  for(let data of this){
    newMap[indexer] = await iteratorFunction(data, indexer, this)
    indexer++
  }
  return newMap
}

Array.prototype.asyncMap = asyncMap

... 等々 :)

注意すべきいくつかの事柄:

  • iteratorFunctionは非同期関数またはpromiseである必要があります
  • 以前Array.prototype.<yourAsyncFunc> = <yourAsyncFunc>に作成されたアレイでは、この機能を利用できません
3
PranavKAndro 2019-11-25 10:31.

今日、私はこれに対する複数の解決策に出くわしました。forEachループで非同期待機関数を実行します。ラッパーを構築することで、これを実現できます。

ネイティブのforEachについて、内部でどのように機能するか、非同期関数呼び出しを実行できない理由、およびさまざまなメソッドに関するその他の詳細については、こちらのリンクを参照してください。

それを行うことができる複数の方法とそれらは次のとおりです、

方法1:ラッパーを使用します。

await (()=>{
     return new Promise((resolve,reject)=>{
       items.forEach(async (item,index)=>{
           try{
               await someAPICall();
           } catch(e) {
              console.log(e)
           }
           count++;
           if(index === items.length-1){
             resolve('Done')
           }
         });
     });
    })();

方法2:Array.prototypeのジェネリック関数と同じものを使用する

Array.prototype.forEachAsync.js

if(!Array.prototype.forEachAsync) {
    Array.prototype.forEachAsync = function (fn){
      return new Promise((resolve,reject)=>{
        this.forEach(async(item,index,array)=>{
            await fn(item,index,array);
            if(index === array.length-1){
                resolve('done');
            }
        })
      });
    };
  }

使用法 :

require('./Array.prototype.forEachAsync');

let count = 0;

let hello = async (items) => {

// Method 1 - Using the Array.prototype.forEach 

    await items.forEachAsync(async () => {
         try{
               await someAPICall();
           } catch(e) {
              console.log(e)
           }
        count++;
    });

    console.log("count = " + count);
}

someAPICall = () => {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve("done") // or reject('error')
        }, 100);
    })
}

hello(['', '', '', '']); // hello([]) empty array is also be handled by default

方法3:

Promise.allの使用

  await Promise.all(items.map(async (item) => {
        await someAPICall();
        count++;
    }));

    console.log("count = " + count);

方法4:従来のforループまたは最新のforループ

// Method 4 - using for loop directly

// 1. Using the modern for(.. in..) loop
   for(item in items){

        await someAPICall();
        count++;
    }

//2. Using the traditional for loop 

    for(let i=0;i<items.length;i++){

        await someAPICall();
        count++;
    }


    console.log("count = " + count);
3
richytong 2020-05-21 10:57.

を使用できますArray.prototype.forEachが、async / awaitにはそれほど互換性がありません。これは、非同期コールバックから返されたpromiseが解決されることを期待しているがArray.prototype.forEach、そのコールバックの実行からのpromiseを解決しないためです。したがって、forEachを使用できますが、Promiseの解決を自分で処理する必要があります。

これは、を使用して各ファイルを連続して読み取って印刷する方法です。 Array.prototype.forEach

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

  let promiseChain = Promise.resolve()
  files.forEach((file) => {
    promiseChain = promiseChain.then(() => {
      fs.readFile(file, 'utf8').then((contents) => {
        console.log(contents)
      })
    })
  })
  await promiseChain
}

これが(まだ使用しているArray.prototype.forEach)ファイルの内容を並行して印刷する方法です

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

  const promises = []
  files.forEach((file) => {
    promises.push(
      fs.readFile(file, 'utf8').then((contents) => {
        console.log(contents)
      })
    )
  })
  await Promise.all(promises)
}
2
jgmjgm 2019-10-15 08:35.

それがどのようにうまくいかないかを確認するには、メソッドの最後にconsole.logを出力します。

一般的にうまくいかないことがあります:

  • 任意の順序。
  • printFilesは、ファイルを印刷する前に実行を終了できます。
  • 業績不振。

これらは常に間違っているわけではありませんが、多くの場合、標準的なユースケースにあります。

通常、forEachを使用すると、最後を除くすべての結果になります。関数を待たずに各関数を呼び出します。つまり、すべての関数に開始を指示し、関数の終了を待たずに終了します。

import fs from 'fs-promise'

async function printFiles () {
  const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'))

  for(const file of files)
    console.log(await file)
}

printFiles()

これは、順序を維持し、関数が途中で戻るのを防ぎ、理論的には最適なパフォーマンスを維持するネイティブJSの例です。

この意志:

  • すべてのファイル読み取りを開始して、並行して実行します。
  • mapを使用してファイル名を待機する約束にマップすることにより、順序を保持します。
  • 配列で定義された順序で各promiseを待ちます。

このソリューションでは、最初のファイルが利用可能になるとすぐに、他のファイルが最初に利用可能になるのを待たずに表示されます。

また、2番目のファイルの読み取りを開始する前に、最初のファイルが終了するのを待つ必要はなく、すべてのファイルを同時にロードします。

これと元のバージョンの唯一の欠点は、一度に複数の読み取りが開始されると、一度に発生する可能性のあるエラーが増えるため、エラーの処理がより困難になることです。

一度にファイルを読み取るバージョンでは、それ以上ファイルを読み取ろうとして時間を無駄にすることなく、失敗時に停止します。精巧なキャンセルシステムを使用しても、最初のファイルで失敗するのを避けるのは難しいかもしれませんが、他のほとんどのファイルもすでに読み取っています。

パフォーマンスは常に予測できるとは限りません。多くのシステムは並列ファイル読み取りの方が高速ですが、一部のシステムはシーケンシャルを好みます。一部は動的であり、負荷がかかるとシフトする可能性があります。遅延を提供する最適化は、激しい競合の下で常に良好なスループットをもたらすとは限りません。

この例では、エラー処理もありません。何かがそれらをすべて正常に表示するか、まったく表示しないようにする必要がある場合、それは行われません。

各段階でconsole.logを使用し、偽のファイル読み取りソリューション(代わりにランダム遅延)を使用して、詳細な実験を行うことをお勧めします。多くのソリューションは単純なケースでも同じように見えますが、すべてに微妙な違いがあり、絞り出すためにさらに精査する必要があります。

このモックを使用して、ソリューション間の違いを識別します。

(async () => {
  const start = +new Date();
  const mock = () => {
    return {
      fs: {readFile: file => new Promise((resolve, reject) => {
        // Instead of this just make three files and try each timing arrangement.
        // IE, all same, [100, 200, 300], [300, 200, 100], [100, 300, 200], etc.
        const time = Math.round(100 + Math.random() * 4900);
        console.log(`Read of ${file} started at ${new Date() - start} and will take ${time}ms.`)
        setTimeout(() => {
          // Bonus material here if random reject instead.
          console.log(`Read of ${file} finished, resolving promise at ${new Date() - start}.`);
          resolve(file);
        }, time);
      })},
      console: {log: file => console.log(`Console Log of ${file} finished at ${new Date() - start}.`)},
      getFilePaths: () => ['A', 'B', 'C', 'D', 'E']
    };
  };

  const printFiles = (({fs, console, getFilePaths}) => {
    return async function() {
      const files = (await getFilePaths()).map(file => fs.readFile(file, 'utf8'));

      for(const file of files)
        console.log(await file);
    };
  })(mock());

  console.log(`Running at ${new Date() - start}`);
  await printFiles();
  console.log(`Finished running at ${new Date() - start}`);
})();

0
Scott Rudiger 2018-06-22 06:55.

Antonio Valと同様にp-iteration、代替のnpmモジュールはasync-af次のとおりです。

const AsyncAF = require('async-af');
const fs = require('fs-promise');

function printFiles() {
  // since AsyncAF accepts promises or non-promises, there's no need to await here
  const files = getFilePaths();

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

printFiles();

または、async-afpromiseの結果をログに記録する静的メソッド(log / logAF)があります。

const AsyncAF = require('async-af');
const fs = require('fs-promise');

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

  AsyncAF(files).forEach(file => {
    AsyncAF.log(fs.readFile(file, 'utf8'));
  });
}

printFiles();

ただし、ライブラリの主な利点は、非同期メソッドをチェーンして次のようなことを実行できることです。

const aaf = require('async-af');
const fs = require('fs-promise');

const printFiles = () => aaf(getFilePaths())
  .map(file => fs.readFile(file, 'utf8'))
  .forEach(file => aaf.log(file));

printFiles();

async-af

Related questions

MORE COOL STUFF

「水曜日」シーズン1の中心には大きなミステリーがあります

「水曜日」シーズン1の中心には大きなミステリーがあります

Netflixの「水曜日」は、典型的な10代のドラマ以上のものであり、実際、シーズン1にはその中心に大きなミステリーがあります.

ボディーランゲージの専門家は、州訪問中にカミラ・パーカー・ボウルズが輝くことを可能にした微妙なケイト・ミドルトンの動きを指摘しています

ボディーランゲージの専門家は、州訪問中にカミラ・パーカー・ボウルズが輝くことを可能にした微妙なケイト・ミドルトンの動きを指摘しています

ケイト・ミドルトンは、州の夕食会と州の訪問中にカミラ・パーカー・ボウルズからスポットライトを奪いたくなかった、と専門家は言う.

一部のファンがハリー・スタイルズとオリビア・ワイルドの「非常に友好的な」休憩が永続的であることを望んでいる理由

一部のファンがハリー・スタイルズとオリビア・ワイルドの「非常に友好的な」休憩が永続的であることを望んでいる理由

一部のファンが、オリビア・ワイルドが彼女とハリー・スタイルズとの間の「難しい」が「非常に友好的」な分割を恒久的にすることを望んでいる理由を見つけてください.

エリザベス女王の死後、ケイト・ミドルトンはまだ「非常に困難な時期」を過ごしている、と王室の専門家が明らかにする 

エリザベス女王の死後、ケイト・ミドルトンはまだ「非常に困難な時期」を過ごしている、と王室の専門家が明らかにする&nbsp;

エリザベス女王の死後、ケイト・ミドルトンが舞台裏で「非常に困難な時期」を過ごしていたと伝えられている理由を調べてください.

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セントヘレナのジェイコブのはしごを登るのは、気弱な人向けではありません

セント ヘレナ島のジェイコブズ ラダーは 699 段の真っ直ぐ上る階段で、頂上に到達すると証明書が発行されるほどの難易度です。

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

Total War:Warhammer:Kotakuレビュー

Total War:Warhammer:Kotakuレビュー

私はこのゲームを嫌う準備ができていました。先週の前に、Total War:Warhammerについての私の考えがありました:それでもここに私は、私の手にある完成品であり、私は変わった男です。

涙の道:軍事化された帝国主義勢力がスタンディングロックキャンプを占領

涙の道:軍事化された帝国主義勢力がスタンディングロックキャンプを占領

スタンディングロックスー族のメンバーと水の保護者は、ノースダコタ州のスタンディングロックにあるオセティサコウィンキャンプを去ります。(Twitter経由のCNNスクリーンショット)火と煙がスカイラインを覆い、スタンディングロックスー族のメンバーと水の保護者が、聖なるものを守りながら建てた家、オセティサコウィン(セブンカウンシルファイアーズ)キャンプから行進し、太鼓を打ち、歌い、祈りました。ダコタアクセスパイプラインとしても知られる「ブラックスネーク」からの土地。

シアーズとKマートはイヴァンカ・トランプの商品を自分たちで取り除いています

シアーズとKマートはイヴァンカ・トランプの商品を自分たちで取り除いています

写真:APシアーズとKマートは、イヴァンカ・トランプのトランプホームアイテムのコレクションも、誰も購入したくないために削除しました。シアーズとKマートの両方の親会社であるシアーズホールディングスは、土曜日のABCニュースへの声明で、彼らが気にかけていると辛抱強く説明しましたトランプラインを売り続けるにはお金を稼ぐことについてあまりにも多く。

ポテトチップスでたった10分でスペインのトルティーヤを作る

ポテトチップスでたった10分でスペインのトルティーヤを作る

伝統的なスペインのトルティーヤは通常、オリーブオイルで柔らかくなるまで調理されたポテトから始まります(30分以上かかる場合があります)が、ケトルで調理されたポテトチップスの助けを借りてわずか10分でテーブルに置くことができます。上のビデオはすべてがバラバラにならないように裏返す方法を含め、レシピ全体を説明しますが、必要なのは4〜5個の卵と3カップのケトルチップスだけです。

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、彼らが子供たちと行っているスパイをテーマにした活動を共有しています

ケイト・ミドルトンとウィリアム王子は、子供向けのパズルの本の序文を書き、ジョージ王子、シャーロット王女、ルイ王子と一緒にテキストを読むと述べた.

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

事故で押しつぶされたスイカは、動物を喜ばせ水分補給するために野生生物保護団体に寄付されました

Yak's Produce は、数十個のつぶれたメロンを野生動物のリハビリ専門家であるレスリー グリーンと彼女のルイジアナ州の救助施設で暮らす 42 匹の動物に寄付しました。

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

デミ・ロヴァートは、新しいミュージシャンのボーイフレンドと「幸せで健康的な関係」にあります: ソース

8 枚目のスタジオ アルバムのリリースに向けて準備を進めているデミ ロヴァートは、「スーパー グレート ガイ」と付き合っている、と情報筋は PEOPLE に確認しています。

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

Plathville の Kim と Olivia Plath が数年ぶりに言葉を交わすことへようこそ

イーサン プラスの誕生日のお祝いは、TLC のウェルカム トゥ プラスビルのシーズン 4 のフィナーレで、戦争中の母親のキム プラスと妻のオリビア プラスを結びつけました。

仕事の生産性を高める 8 つのシンプルなホーム オフィスのセットアップのアイデア

仕事の生産性を高める 8 つのシンプルなホーム オフィスのセットアップのアイデア

ホームオフィスのセットアップ術を極めよう!AppExert の開発者は、家族全員が一緒にいる場合でも、在宅勤務の技術を習得しています。祖父や曽祖父が共同家族で暮らしていた頃の記憶がよみがえりました。

2022 年、私たちのデジタル ライフはどこで終わり、「リアル ライフ」はどこから始まるのでしょうか?

20 年前のタイムトラベラーでさえ、日常生活におけるデジタルおよびインターネットベースのサービスの重要性に驚くことでしょう。MySpace、eBay、Napster などのプラットフォームは、高速化に焦点を合わせた世界がどのようなものになるかを示してくれました。

ニューロマーケティングの秘密科学

ニューロマーケティングの秘密科学

マーケティング担当者が人間の欲望を操作するために使用する、最先端の (気味が悪いと言う人もいます) メソッドを探ります。カートをいっぱいにして 3 桁の領収書を持って店を出る前に、ほんの数点の商品を買いに行ったことはありませんか? あなたは一人じゃない。

地理情報システムの日: GIS 開発者として学ぶべき最高の技術スタック

地理情報システムの日: GIS 開発者として学ぶべき最高の技術スタック

私たちが住んでいる世界を確実に理解するには、データが必要です。ただし、空間参照がない場合、このデータは地理的コンテキストがないと役に立たなくなる可能性があります。

Language