Создать асинхронную функцию для последующего вызова результата в экспресс-маршруте - PullRequest
0 голосов
/ 17 июня 2019

Мне нужно получить файл Excel с Box.com через API и преобразовать Excel в JSON.Позже этот JSON будет отображаться с помощью Express и Handlebars.

Я создал следующую функцию для извлечения Excel / JSON:

let getExternalFile = async () => {
  const stream = await client.files.getReadStream('123456789');
  const external = await fs.createWriteStream('/external.xlsx');
  stream.pipe(external);
  let finished = await external.on('finish', async () => {
    const excel = await excelToJson({
      source: fs.readFileSync(external.path),
      header: {
        rows: 1
      },
      columnToKey: {
        A: "edate",
        B: "esource"
      },
      sheets: ['Sheet1']
    });
    console.log(excel);
    return excel
  })
}

Теперь моя проблема в том, что я не знаю, какразрешите ожидающее обещание, когда я сделаю это:

let testData = getExternalFile();
console.log(testData); // Promise { <pending> }

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

app.get('/', (req, res) => {
    res.render('stories.ejs', {
        msg: "Welcome to stories.ejs", 
        odata: odata, 
        edata: edata,
        ...
    });
});

Должен ли я обернуть его в анонимную асинхронную функцию, чтобы вызвать его?

1 Ответ

2 голосов
/ 17 июня 2019

async / await не является панацеей для всех вещей асинхронных. Они были предназначены для работы только с Обещаниями. В частности, async / await не работает с источниками событий. Правильная реализация getExternalFile должна быть:

let getExternalFile = async () => {
  const stream = client.files.getReadStream('123456789'); // no await here
  const external = fs.createWriteStream('/external.xlsx'); // no await here
  stream.pipe(external);

  let finished = new Promise ((resolve, reject) => {
    external.on('finish', async () => { // cannot use await here
      const excel = await excelToJson({
        source: fs.readFileSync(external.path),
        header: {
          rows: 1
        },
        columnToKey: {
          A: "edate",
          B: "esource"
        },
        sheets: ['Sheet1']
      });
      console.log(excel);

      resolve(excel);
    })
  });

  return finished; // return the promise so you can await it later
}

Все не обещающие функции (я не буду называть их не «асинхронными», потому что это будет путать людей с разницей между асинхронными асинхронными функциями и неасинхронными асинхронными функциями, потому что люди иногда используют «асинхронный» для обозначения асинхронных, а иногда и для имею в виду ключевое слово "async", которое является функциями, генерирующими обещания) ... Я отвлекся ... все функции без обещаний не работают с await. Это включает в себя такие вещи, как источники событий x.on('some_event' ... ).

В таких случаях вам нужно будет обернуть их в new Promise(), чтобы преобразовать их в Обещания.

Теперь, когда мы переписали вышеуказанную функцию, мы можем просто дождаться результата:

app.get('/', async /* <--IMPORTANT */ (req, res) => {
    let testData = await getExternalFile(); // use await here!!

    // ...
});

Если у вас несколько ожиданий, функция может работать медленно:

app.get('/', async /* <--IMPORTANT */ (req, res) => {
    let testData = await getExternalFile();
    let testData2 = await getExternalFile2(); // SLOW!

    // ...
});

Если вам это удастся, вы можете параллельно выполнять асинхронные функции:

app.get('/', async /* <--IMPORTANT */ (req, res) => {
    let testDataArray = await Promise.all([
        getExternalFile(), getExternalFile2()  // FAST!
    ]);

    // ...
});

Эполог: Ошибки

В реальном коде вы должны отлавливать ошибки в коде, который вы ожидаете, чтобы предотвратить сбой вашего сервера:

app.get('/', async /* <--IMPORTANT */ (req, res) => {
    try {
        let testData = await getExternalFile(); // use await here!!

        // ...
    }
    catch (err) {

        // ...
    }
});

В качестве альтернативы вы можете использовать промежуточное ПО, такое как express-async-handler , для перехвата асинхронных ошибок.

...