в async/await? Я пытаюсь перебрать массив файлов и forEach на содержание каждого файла. 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 Конечно, код работает, но я уверен, что он не работает так, как вы ожидаете. Он просто запускает несколько асинхронных вызовов, но указатель контекста выполнения

сразу же возвращается после этого. printFiles Если вы хотите читать файлы последовательно,

Вы не можете использовать Для обработчиков событий: forEach встроенные обработчики событий, такие как цикл for … of будет работать так, как ожидалось: await Существует много недоразумений относительно того, как

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

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

«это» Для обработчиков событий: forEach Вызов функции обратного вызова возвращает обещание, но вы отбрасываете их, а не ожидаете. Просто используйте async, и вы можете ожидать массив обещаний, которые вы получите с 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)
  }));
}

С ES2018 вы можете значительно упростить все вышеперечисленные ответы на:

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

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

см. В спецификации: https://github.com/tc39/proposal-async-iteration


2018-09-10: этот ответ получал много внимания в последнее время, пожалуйста, смотрите сообщение в блоге Акселя Раушмайера для получения дополнительной информации об асинхронной итерации: Http://2ality.com/2016/10/asynchronous-iteration.html

вместо Promise.all в сочетании с Array.prototype.map (который не гарантирует порядок, в котором разрешаются Promise), я использую Array.prototype.reduce, начиная с разрешенного 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());
}

Переменная p-итерацией в npm, реализует методы итераций массива, поэтому они могут использоваться в очень простой способ с помощью 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);
  });
})();

Вот некоторые 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));
}

Примечание , хотя вы можете включать это в свой собственный код, вы не должны включать это в библиотеки, которые вы распространяете среди других (чтобы не загрязнять их глобальные переменные) .

Оба вышеупомянутых решения работают, однако, Антонио работает с меньше кода, вот как это помогло мне разрешить данные из моей базы данных, от нескольких разных дочерних ссылок, а затем поместить их все в массив и разрешить их в обещании после того, как все будет сделано:

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)))

сейчас, при условии, что это сохранено в ‘./myAsync.js’, вы можете сделать что-то похожее на приведенное ниже в соседнем файле:

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

(то есть функция, {{}} одна важная

...
/* 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));
}

caveat : метод в то время как создание объекта с помощью «нового» await for .. of способа на самом деле имеют различный эффект. forEach async Следующее описывает каждый из этих контекстов один за другим:

Global Context await ( т.е. вне всех функций): for Вне всех функций (т. е. в глобальном контексте) forEach async «currenttobject» (и, следовательно, значение (меньше элегантно) если вы не используете

и хотите чтобы убедиться, что файлы читаются reduce promise «window» async/await объект для браузеров. Внутри прямого вызова «Не связанная функция», Глядя на вывод

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

объект, который вызвал вызов функции, становится «текущим объектом»

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

(и, следовательно, значение

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 */
}

Если вам действительно нужна большая гибкость в кодировании, вы можете просто сделать это (для забавы, я использую предложенный оператор Pipe Forward объект (для нестрогого режима) или

import { curry, flip } from 'ramda'

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

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

undefined

(для строгого режима). Любая функция (или переменная), определенная в ответе , автоматически становится свойством объекта. Например, предположим, что функция определяется в глобальном контексте как readFile оно становится свойством объекта окна, как если бы вы определили его как

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);
}

в «нестрогом режиме», не требует вызова или вызова этой функции напрямую через .map() «UserDefinedFunction ()» async автоматически вызовет / invokeit, поскольку fs.readFile «window.UserDefinedFunction ()» promises, создавая Promise.all() Глядя на вывод

как после возврата функции * * все локальные переменные больше не доступны, потому что стековый фрейм уничтожен. «UserDefinedFunction «files. Вызов этой функции в «Не строгом режиме» приведет к следующему

В «Строгом режиме» вызов / вызов функции напрямую через

// 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}

will

«NOT»

// 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

автоматически вызывать / вызывать его как {* } … и так далее :)

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

Некоторые замечания:

(и значением

  • любых массивов, созданных до
  • эта функция не будет доступна Array.prototype.<yourAsyncFunc> = <yourAsyncFunc> аналогичен

. Вызов этой функции в «строгом режиме» приведет к следующему p-iteration. Однако ее явный вызов с использованием объекта window приведет к следующему 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();

имеет статический метод (log / logAF), который регистрирует результаты обещаний: async-af Тем не менее, основное преимущество библиотеки заключается в том, что вы может связывать асинхронные методы, чтобы сделать что-то вроде:

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

хорошо работает, когда принимает значение fs и значение его свойств bluebird, fs-extra или fs-promise Однако решение для собственной

библиотеки узла заключается в следующем: fs «c»

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') «d»

TypeError [ERR_INVALID_CALLBACK]: Callback must be a function

pify { *} были показаны как не определяет эти свойства и Аналогично, когда . Я видел, как несколько разработчиков тратили время на воссоздание своих методов или, что еще хуже, создание сложного в обслуживании асинхронного кода, когда асинхронные методы более высокого порядка упростят код. его документы . Я видел, как несколько разработчиков тратили время на воссоздание своих методов или, что еще хуже, создание сложного в обслуживании асинхронного кода, когда асинхронные методы более высокого порядка упростят код.

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
```