【问题标题】:How to make code wait for response before continue a nested promise?如何在继续嵌套承诺之前让代码等待响应?
【发布时间】:2021-08-04 00:46:17
【问题描述】:

我有一些类似于以下的代码:

functionA (list) {
  list.forEach(fucntion (item) {
    functionB(item);
  });
}

functionB (item) {
  // format data
  service.init(item) // first promise
    .then(function (data) {
      // error handle
      (functionC (randomStuff) {
        // error handle
        service.getResponse(data) // second promise
          .then(function (response) {
            // this is the response value I need to pass back
          })
      })()
    }
})

我需要在开始时让 forEach 循环发送一个项目并等待响应,然后再继续处理列表中的下一个项目。关于如何实现这一点的任何想法?

【问题讨论】:

    标签: javascript asynchronous promise


    【解决方案1】:

    您可以使用 asyncawait 关键字使您的函数异步,这样您就可以在函数中同步地解析 Promise:

    async functionB(item) {
      var data = await service.init(item);
    
      (async functionC(randomStuff) {
        var response = await service.getResponse(data);
        return response;
      })();
    }
    

    文档:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

    【讨论】:

    • FunctionC 在第一个 promise 的 .then 中,你将如何更新你的解决方案来处理它?
    • await 关键字将使函数等待 promise 返回的值被解析为变量,所以就像您使用 .then 一样。解决方案应该是这样的
    • 好的,那么让函数 B 让函数 A 知道它可以继续到列表中的下一项?
    • 是的。 foreach 只会在 functionB 结束时继续
    【解决方案2】:

    从您的问题推断出每个异步函数调用都取决于先前调用的结果,您可以在 for 循环中创建一系列承诺,如下所示...

    function functionA(list) {
      let promiseChain = Promise.resolve();
      list.forEach(item => {
        promiseChain = promiseChain.then(result => {
          return functionB(item, result);
        });
      });
      return promiseChain;
    }
    

    像这样顺序链接的一个原因是异步函数的每次调用都需要最后一次调用的结果。所以在这里,functionB 接受当前项目和先前的结果。

    // this function must work when priorResult == null, as it will be on the first invocation
    function functionB(item, priorResult) {
      return service.init(item).then(data => { // note the returns, which are missing in the OP pseudo-code
        return service.getResponse(data);
      });
    }
    

    【讨论】:

    • 提供的解决方案在代码库中不起作用
    【解决方案3】:

    您可以使用for of 循环在functionA 中使用asyncawait 完成您的工作。

    (async function functionA(list) {
      try {
        for (const item of list) {
          const response = await functionB(item);
          //do something with response...
          console.log(response);
        }
      } catch (err) {
        console.log(err);
      }
    })(list);
    
    async function functionB(item) {
      try {
        const randomStuff = "test";
        const data = await service.init(item);
        const response = await functionC(randomStuff)(data);
        return response;
      } catch (err) {
        throw err;
      }
    }
    
    function functionC(randomStuff) {
      return async data => {
        try {
          const response = await service.getResponse(data); // second promise
          return response;
        } catch (err) {
          throw err;
        }
      };
    }
    

    【讨论】:

    • 无法移除函数B,因为它会破坏其他使用该函数的地方
    • @adarian,我更新了我的答案,添加了函数 B。
    猜你喜欢
    • 2017-07-31
    • 1970-01-01
    • 2018-12-14
    • 1970-01-01
    • 2017-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-17
    相关资源
    最近更新 更多