首页 > 解决方案 > 将 promise 函数重构为 es6 格式,await 实际上并没有 await

问题描述

所以我只是重新审视一些旧代码来整理和现代化我的Partum-React项目中的一些语法。但是,当我将这个特定的旧传统格式重新格式化function() return new Promise...async () => ...return...类型函数时,它似乎并没有等待函数完成。我找到的答案似乎没有解决我的问题,因为据我所知,我的异步函数编写正确并且应该按预期工作。我还已经将一些较旧的函数/承诺函数重新格式化为异步函数,没有问题。所以我很困惑为什么这个特定的功能似乎没有被正确地包装在一个承诺中。

旧功能按预期工作,程序在继续执行之前正确等待功能完成(在helper.js文件/src夹中找到):

function shell(command, log = false, cb = null) {
  return new Promise((resolve, reject) => {
    exec(command, (err, stdout, stderr) => {
      if (err) {
        reject(err);
      } else {
        if (cb) cb(stdout);
        if (log) process.stdout.write(`\n${stdout}\n\n`);
        resolve({
          stdout,
          stderr,
        });
      }
    });
  });
}

重写的函数,用 await 调用时似乎没有正确等待。连续shell调用同步运行导致 git 出错。我确信这是我的一个小错误,但我似乎看不到它。据我所知,这个函数应该被正确地包装在一个 promise 和函数中:

const shell = async (command, log = false, cb = null) => {
  exec(command, (err, stdout, stderr) => {
    if (err) throw err;
    if (cb) cb(stdout);
    if (log) process.stdout.write(`\n${stdout}\n\n`);
    return {
      stdout,
      stderr,
    };
  });
};

这是调用函数的地方(在initializer.js文件/src夹中找到)(我知道,这也需要一些重大清理):

finalize() {
    return new Promise((resolve, reject) => {
      process.stdout.write('finalizing project\n');
      copy(this.tempPath, this.destination, (err) => {
        if (err) {
          reject(err);
        } else {
          process.stdout.write('cleaning up temporary files\n');
          rmdir(this.tempPath, async (err) => { // eslint-disable-line
            if (err) {
              reject(err);
            } else {
              try {
                await shell(`mkdir ${path.join(this.destination, this.options.componentPath)}`);

                if (this.options.redux) {
                  await shell(`mkdir ${path.join(this.destination, this.options.reduxPath, this.options.actionPath)}`);
                }

                await shell(`git -C ${this.destination} init`);
                await shell(`git -C ${this.destination} add .`);
                await shell(`git -C ${this.destination} commit -m 'Initialized with Partum-React'`);

                process.stdout.write(
                  `\nrunning npm install inside ${this.destination}\n`,
                );
                await npmInstall(this.destination, this.silent);

                resolve(true);

              } catch (err) { // eslint-disable-line
                reject(err);
              }
            }
          });
        }
      });
    });
  }
};

shell(....)没有等待日志的控制台日志记录Promise {undefined}

await shell(....)带有等待日志的控制台日志记录{undefined}

提前感谢您对此提供的任何帮助!

标签: javascriptecmascript-6async-awaites6-promise

解决方案


不,您的async函数编写不正确。您不能用/语法替换new Promise构造函数asyncawait。如果某些东西只提供了一个回调 API,那么您需要在能够使用它之前对其进行承诺await

你应该做

function shell(command) {
  return new Promise((resolve, reject) => {
    exec(command, (err, stdout, stderr) => {
      if (err) {
        reject(err);
      } else {
        resolve({stdout, stderr});
      }
    });
  });
}
function copy(source, destination) {
  return new Promise((resolve, reject) => {
    …
  });
}
function rmdir(path) {
  return new Promise((resolve, reject) => {
    …
  });
}

然后你可以finalise使用async/编写你的函数await

async finalize() {
  process.stdout.write('finalizing project\n');
  await copy(this.tempPath, this.destination);
  process.stdout.write('cleaning up temporary files\n');
  await rmdir(this.tempPath);
  await shell(`mkdir ${path.join(this.destination, this.options.componentPath)}`);
  if (this.options.redux) {
    await shell(`mkdir ${path.join(this.destination, this.options.reduxPath, this.options.actionPath)}`);
  }
  await shell(`git -C ${this.destination} init`);
  await shell(`git -C ${this.destination} add .`);
  await shell(`git -C ${this.destination} commit -m 'Initialized with Partum-React'`);
  process.stdout.write(`\nrunning npm install inside ${this.destination}\n`);
  await npmInstall(this.destination, this.silent);
  return true;
}

推荐阅读