Вложенное асинхронное выполнение не работает должным образом

#javascript #node.js

Вопрос:

У меня есть функция, которая отправит все изображения, расположенные в папке «образцы», в функцию extractImage, затем функция extractImage вызовет сторонний API для выполнения своей операции. Но когда я пытаюсь console.log(arr), кажется, что он даже не вызывался. Я думаю, что я сделал что-то не так с обработкой асинхронности, не мог бы кто-нибудь помочь мне взглянуть. У меня есть быстрое новое в JavaScript.

 let arr = [];

await fs.readdir("samples", async (err, files) => {
  console.log(files);
  files.map(async (val) => {
    console.log(val);
    let tt = await extractImage(val);
    return arr.push(tt);
  });
});

fs.writeFileSync("final.json", "s");

console.log(arr);
console.log("tt");
 

Комментарии:

1. Это первое ожидание не находится внутри асинхронной функции, поэтому оно не даст желаемого результата

2. Вы неправильно использовали fs.readdir (), и это должно быть const files = await readdir(path);

Ответ №1:

Вы неправильно использовали fs.readdir (), и так и должно быть const files = await readdir(path) . И вы files.map(async (val) => {...}) немедленно вернете список обещаний, которые console.log(arr) могут быть выполнены еще до того, как эти обещания будут выполнены. Код может быть похож на следующий:

 
let files = await fs.readdir("samples")
console.log(files);

let promises = files.map(async (val) => {
    let tt = await extractImage(val);
    return tt;
});

let arr = await Promise.all(promises)
console.log(arr);
console.log("tt");

fs.writeFileSync("final.json", "s");

 

Ответ №2:

Я мог бы рассмотреть возможность использования promisify в этом случае, а затем возврата массива обещаний из файлов и получения ваших данных, когда все они будут решены.

 const util = require('util');
const fs = require('fs');

const readdirP = util.promisify(fs.readdir);

async function main() {
  try {
    const files = await readdirP('samples');
    const promises = files.map(file => extractImage(file));
    const data = await Promise.all(promises);
  } catch(error) {
    console.log(error);
  }
}

main();
 

Ответ №3:

Редактировать:

  1. await не может использоваться в глобальном контексте.
  2. fs.readdir не возвращает обещания. Он основан на обратном вызове, что означает, что вы не можете его ждать. Однако существует синхронная версия метода: fs.readdirSync .
  3. Начиная с узла 11, вы можете сделать это:
 const fs = require('fs').promises
 

что позволяет использовать await и .затем на fs. Для более низких версий вы можете использовать util.promisify .

Комментарии:

1. Как я проверил, fs.readdir() не поддерживает .затем()

Ответ №4:

В этом случае может помочь использование функции, вызываемой самостоятельно:

 (async function () {
  let arr = [];
  await fs.readdir("samples", async (err, files) => {
    console.log(files);
    files.map(async (val) => {
      console.log(val);
      let tt = await extractImage(val);
      return arr.push(tt);
    });
  });
  fs.writeFileSync("final.json", "s");
  console.log(arr);
  console.log("tt");
});
 

Комментарии:

1. Я уже тестировал это решение раньше, но, похоже, console.log(arr); не дождался завершения fs.readdir()