【问题标题】:Avoiding nested promises inside a then function JS避免在 then 函数 JS 中嵌套 promise
【发布时间】:2018-04-10 11:09:59
【问题描述】:

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

doSomething()
  .then(() => {
    return doApiRequest();
  })
  .then((apiResult) => {
    doSomethingElse(apiResult);
  });

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

doSomething()
  .then(() => {
    return waitForRateRefresh();
  })
  .then(() => {
    return doApiRequest();
  })
  .then((apiResult) => {
    doSomethingElse(apiResult);
  });

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

'doApiRequest' 看起来像这样

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

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

return waitForRateRefresh().then(() => new Promise(..../http call));

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

感谢您的任何见解

【问题讨论】:

  • 注意:'doApiRequest' would look something like this 避免使用承诺构造函数反模式...该函数的内容只是return waitForRateRefresh().then(() => { //http call return someValue; };
  • 看到你.then(() => { return waitForRateRefresh(); }) 和doApiRequest 一样......无论如何都没有传入的“价值”
  • @JaromandaX 绝对是,在这种情况下,虽然 'someValue' 会使其成为原始 then 语句,或者只会返回 waitForRateRefresh 解析为的内容
  • 这很有帮助,尤其是能够包装它。我在这里创建了一个 JSBin 来测试一些不同的方法并返回值jsbin.com/dawesen/edit?js,console

标签: javascript node.js promise async-await


【解决方案1】:

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

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

假设你真的想将doSomething 的结果传递给doApiRequest,你可以做什么

doSomething()
.then(result => waitForRateRefresh().then(() => result))
.then((doSomethingResult) => doApiRequest(doSomethingResult))
.then((apiResult) => doSomethingElse(apiResult));

当然,上面的可以简化为

doSomething()
.then(result => waitForRateRefresh().then(() => result))
.then(doApiRequest)
.then(doSomethingElse);

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

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

这被简化为

doApiRequest(){
    return waitForRateRefresh().then(() => {
        //http call
        return someValue;
    };
}

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

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

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

现在是主要代码

doSomething()
.then(doApiRequest)
.then(doSomethingElse);

同样,尽管...如果 someValue 在任何 http call 中异步收集,//http call 和 return someValue 将无法正常工作


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

围绕doApiRequest创建一个“包装器”

const qApiRequest = result => waitForRateRefresh().then(() => doApiRequest(result));

现在,代码是

doSomething()
.then(qApiRequest)
.then(doSomethingElse);

当然,async/await 只是

const doSomethingResult = await doSomething();
await waitForRateRefresh();
const apiResult = doApiRequest(doSomethingResult);
const finalResult = doSomethingElse(apiResult);

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

【讨论】:

  • 感谢您的回答,澄清您的回答的第二部分使得 .then(result => waitForRateRefresh().then(() => result)) 部分不是必要正确吗?而 someValue 是在 doApiRequest() 之外看到的内容?
  • 对不起,第二部分不同,让我补充一下如何使用
  • @KyleR - 我添加了第三种可能性,我认为这可能是最好的,因为它不需要重写doApiRequest
  • 这很有帮助,尤其是能够包装它。我在这里创建了一个 JSBin 来测试一些不同的方法并返回值jsbin.com/dawesen/edit?js,console
【解决方案2】:

我会使用async/await,它使代码非常易读,并且可以很容易地推断接下来发生的事情。

await doSomething();
await waitForRateRefresh();
const apiResult  = await doApiRequest();
await doSomethingElse(apiResult);

【讨论】:

    猜你喜欢
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-22
    • 1970-01-01
    • 2020-08-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多