首页 > 解决方案 > 动作英雄动作立即返回

问题描述

我试图理解 ActionHero async/await 的核心概念并遇到很多问题。本质上,在一个动作中,为什么它会立即返回,而不是 500 毫秒后返回?

async run (data) {
  setTimeout(() => data.response.outcome = 'success',500)
}

澄清编辑:这个问题更多的是关于异步执行流程和承诺履行,而不是关于 setTimeout() 的字面使用。它并不是真正特定于 ActionHero,但这是 AH 使用的模式,也是我第一次接触这些概念。提供的答案澄清了某些功能必须包装在一个承诺中,以便它们可以被等待,并且有多种方法可以做到这一点。

标签: node.jsasync-awaitactionhero

解决方案


Because you didn't wait for it to finish.

basically you need to await the setTimeout.

async run (data) {
  await setTimeout(() => data.response.outcome = 'success',500)
}

but that doesn't work because setTimeout is not a promise

You can use a simple sleep function that resolves after a time.

async function sleep (time) {
  return new Promise(resolve => setTimeout(resolve, time));
}

async function run (data) {
  await sleep(500);
  data.response.outcome = 'success';
}

Just like setTimeout, which is a callback api can be made into a promise, streams can be made into promises. Note in both the sleep and readFile examples I'm only using the async keyword to make things clear

  async readFile (file) {
    return new Promise((resolve, reject) => {
      let data = '';
      fs.createReadStream(file)
        .on('data', d => data += d.toString())
        .on('error', reject)
        .on('end', () => resolve(data));
    });
  }

For most functions you can skip the manual promisification and use util.promisify

   const { readFile } = require('fs');
   const { promisify } = require('util');

   const readFileAsync = promisify(readFile);

The key part is that the promises should resolve after the work is done, and that you should wait for it using either await or .then

So for instance to make things clearer the first example

async function run (data) {
  return sleep(500).then(() => data.response.outcome = 'success';);
}

and even

function run (data) {
  return sleep(500).then(() => data.response.outcome = 'success';);
}

are all the same at runtime

So to finish

async function transform (inputFile, targetWidth, targetHeight) {
  return new Promise((resolve, reject) => {
    let transformer = sharp()
      .resize(targetWidth, targetHeight)
      .crop(sharp.strategy.entropy)
      .on('info', { width, height } => console.log(`Image created with dimensions ${height}x${width}`)
      .on('error', reject)
      .on('end', resolve);
    inputFile.pipe(transformer);
  });
}

推荐阅读