链接/嵌套承诺

时间:2019-07-15 15:51:54

标签: javascript promise aws-sdk

我在噩梦中试图束缚aws js sdk。当前,我有以下内容(省略了删除谷壳的任何参数,这些调用独立运行,因此可以放心地假设它们是正确的)

function deploy() {
  return sts.assumeRole().promise()
    .then(() => {
      return new Promise((resolve, reject) => {
        return new Promise((resolve, reject) => {
          AWS.config.update({
            credentials: {
              accessKeyId: data.Credentials.AccessKeyId,
              secretAccessKey: data.Credentials.SecretAccessKey,
              sessionToken: data.Credentials.SessionToken
            }
          });
        resolve();
        })
        .then(() => {
          fsPromise.readFile(packageLocation).then(() => {
            return s3.upload().promise();
          });
        });
    }).then(() => {
      return ebs.createApplicationVersion().promise();
    }).then(() => {
      return ebs.createEnvironment().promise();
    });
};

如果按顺序依次运行每个then,则它们会一起工作,但是当我一起运行它们时,createApplicationVersion调用会失败,因为upload不能正常工作assumeRole完成之前正在尝试上载。我想...

我显然做错了,但是我不清楚是什么。

2 个答案:

答案 0 :(得分:5)

使用promise的过程比必要的复杂得多。请记住,then(以及catchfinally返回新的诺言,这些诺言是根据其处理程序返回的内容来结算的。 new Promise(或thencatch)处理程序中的finally几乎是没有必要的;只需返回您将用(一个值或另一个承诺)解决该承诺的任何内容,然后由then等返回该承诺。等将解决该问题。

如果我假设AWS.config.update()是同步的,则该链应如下所示:

function deploy() {
  return sts.assumeRole().promise()
    .then(() => {
        AWS.config.update();
    })
    .then(() => fsPromise.readFile(packageLocation))
    .then(() => s3.upload().promise())
    .then(() => ebs.createApplicationVersion().promise())
    .then(() => ebs.createEnvironment().promise());
}

该链中的每个步骤都将等待上一步完成。

如果您不希望deployebs.createEnvironment().promise()的实现值来实现其承诺,则添加最终的then处理程序:

    .then(() => ebs.createEnvironment().promise())
    .then(() => { });
}

(在下面的示例中,我假设您要这样做。)

如果AWS.config.update()是异步的并返回一个promise,则这样:

function deploy() {
  return sts.assumeRole().promise()
    .then(() => AWS.config.update())
    .then(() => fsPromise.readFile(packageLocation))
    .then(() => s3.upload().promise())
    .then(() => ebs.createApplicationVersion().promise())
    .then(() => ebs.createEnvironment().promise())
    .then(() => { });
}

或者,当然,在任何相对较新的Node.js版本中(我从fsPromise中猜测,只是一般情况下,这就是Node.js),您可以使用async函数:

async function deploy() {
  await sts.assumeRole().promise();
  await AWS.config.update(); // Or without `await` if it is synchronous and doesn't return a promise
  await fsPromise.readFile(packageLocation);
  await s3.upload().promise();
  await ebs.createApplicationVersion().promise();
  await ebs.createEnvironment().promise();
}

有关此代码以及您在注释中发布的类似代码的旁注:

return new Promise((resolve, reject) => {
  AWS.config.update({
    credentials: {
      accessKeyId: data.Credentials.AccessKeyId,
      secretAccessKey: data.Credentials.SecretAccessKey,
      sessionToken: data.Credentials.SessionToken
    }
  });
  resolve();
})

没有理由在那里使用new Promise。它不会将对AWS.config.update的调用转换为异步调用或类似的调用。 如果出于某种原因您需要在那里的承诺(在这种情况下,您不需要AKAICT),则可以使用Promise.resolve

AWS.config.update(/*...*/);
return Promise.resolve();

但是同样,这里不需要。请记住,promise仅提供一种观察异步过程的结果的方法,它们不会使过程异步。 (他们实际上使异步唯一的事情就是观察结果。)

答案 1 :(得分:1)

您不需要像以前那样嵌套诺言。在黑暗中刺伤,试试这个:

function deploy() {
  return sts.assumeRole().promise()
    .then(() => { AWS.config.update() })
    .then(() => fsPromise.readFile(packageLocation))
    .then(() => s3.upload().promise())
    .then(() => ebs.createApplicationVersion().promise())
    .then(() => ebs.createEnvironment().promise())
};