首页 > 解决方案 > 链接/嵌套承诺

问题描述

我正在做噩梦,试图链接 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完成之前上传。我假设...

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

标签: javascriptpromiseaws-sdk

解决方案


使用 Promise 比必要的复杂得多。请记住,then(and catchand finally)返回基于其处理程序返回的新承诺。new Promisethen(or catchor finally) 处理程序中几乎从不需要;只需返回您将使用(一个值或另一个承诺)解决该承诺的任何内容,以及由thenet 返回的承诺。人。将解决它。

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());
}

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

如果你不想deploy用 的实现值来实现它的承诺ebs.createEnvironment().promise(),那么添加一个最终then处理程序:

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

(我假设您想为以下示例执行此操作。)

或者像这样 ifAWS.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())
    .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 仅提供一种观察异步过程结果的方法,它们不会使过程异步。(他们实际上使异步的唯一事情是观察结果。)


推荐阅读