避免在 then 函数 JS 中嵌套承诺

Kyl*_*e R 0 javascript node.js promise async-await

我有一个异步函数“doApiRequest”,它在“then”函数内部调用...

doSomething()
  .then(() => {
    return doApiRequest();
  })
  .then((apiResult) => {
    doSomethingElse(apiResult);
  });
Run Code Online (Sandbox Code Playgroud)

问题是 doApiRequest 返回一个带有该 API 请求最终结果的 Promise。但是,根据我正在使用的 API 的性质,涉及请求速率限制。我计划通过让每个 API 请求将自身添加到队列来处理这个问题,然后当队列在等待速率限制后释放请求时,API 请求将完成解析。虽然我可以做类似...

doSomething()
  .then(() => {
    return waitForRateRefresh();
  })
  .then(() => {
    return doApiRequest();
  })
  .then((apiResult) => {
    doSomethingElse(apiResult);
  });
Run Code Online (Sandbox Code Playgroud)

我最终可能会收到许多“doApiRequest”调用,因此必须在每个调用上链接“waitForRateRefresh”似乎是一个糟糕的方法,而且我还必须使其工作,以便它可以传递来自先前 then 语句的数据。我想做的是在“doApiRequest”本身内部处理这个问题。

'doApiRequest' 看起来像这样

doApiRequest(){
  return new Promise((resolve, reject) => {
    waitForRateRefresh().then(() => {
      //http call
      resolve(someValue);
    };
  });
}
Run Code Online (Sandbox Code Playgroud)

但是,我正在尝试找到一种不涉及嵌套 Promise 的方法。还有什么其他方法可以解决这个问题。我想到的另一种方法是使用 Async/Await,有没有其他方法可以只用承诺来做到这一点?从“doApiRequest”返回带有附加 then 函数的 Promise 会发生什么(或者甚至可能),例如......

return waitForRateRefresh().then(() => new Promise(..../http call));
Run Code Online (Sandbox Code Playgroud)

在调用“doApiRequest”的原始 then 函数中,它会接收“waitForRateRefresh”返回的值,还是向下遍历附加到它的 then 链的结果。

感谢您的任何见解

Jar*_*a X 5

虽然 async/await 很棒,但如果您使用的是不支持它的旧版 nodejs,那么您要么需要转译async/await代码,要么使用普通的 Promises

不知道你是否见过 transpiled async/ await- 它相当“冗长”

你可以做什么,假设你真的想通过结果doSomethingdoApiRequest是这样的

doSomething()
.then(result => waitForRateRefresh().then(() => result))
.then((doSomethingResult) => doApiRequest(doSomethingResult))
.then((apiResult) => doSomethingElse(apiResult));
Run Code Online (Sandbox Code Playgroud)

当然,上面可以简化为

doSomething()
.then(result => waitForRateRefresh().then(() => result))
.then(doApiRequest)
.then(doSomethingElse);
Run Code Online (Sandbox Code Playgroud)

澄清一个关于promise构造函数反模式的观点

doApiRequest(){
    return new Promise((resolve, reject) => {
        waitForRateRefresh().then(() => {
            //http call
            resolve(someValue);
        };
   });
}
Run Code Online (Sandbox Code Playgroud)

这被简化为

doApiRequest(){
    return waitForRateRefresh().then(() => {
        //http call
        return someValue;
    };
}
Run Code Online (Sandbox Code Playgroud)

当然,如果// http call是异步的,那么return someValue就不能这样使用了。但这也适用于您的代码版本

要在此版本的 doApiRequest 中接受来自 doSomething 的值,请将代码更改为

doApiRequest(someResult){
    return waitForRateRefresh().then(() => {
        //http call - use someResult here
        return someValue;
    };
}
Run Code Online (Sandbox Code Playgroud)

主要代码现在是

doSomething()
.then(doApiRequest)
.then(doSomethingElse);
Run Code Online (Sandbox Code Playgroud)

再一次,虽然......如果在任何情况下异步收集//http call并且return someValue将无法按预期工作someValuehttp call


还有一个想法,这样你就不需要重写现有的函数

创建一个“包装器” doApiRequest

const qApiRequest = result => waitForRateRefresh().then(() => doApiRequest(result));
Run Code Online (Sandbox Code Playgroud)

现在,代码是

doSomething()
.then(qApiRequest)
.then(doSomethingElse);
Run Code Online (Sandbox Code Playgroud)

当然,用async/await它只是

const doSomethingResult = await doSomething();
await waitForRateRefresh();
const apiResult = doApiRequest(doSomethingResult);
const finalResult = doSomethingElse(apiResult);
Run Code Online (Sandbox Code Playgroud)

当然,这些需要在标记的函数内 async