代码之家  ›  专栏  ›  技术社区  ›  Juicy

在多个函数完成后运行回调

  •  1
  • Juicy  · 技术社区  · 8 年前

    我有多个耗时的函数,我希望在它们全部完成后运行一个函数,例如:

    data.x = thisTakes2Seconds();
    data.y = thisTakes5Seconds();
    http.post(data);
    

    我熟悉JavaScript中回调的概念,但是如果我有几个函数,我真的应该有嵌套回调几个函数吗?

    3 回复  |  直到 8 年前
        1
  •  1
  •   Marcos Casagrande    8 年前

    为了方便地处理异步函数,最好的方法是使用 promises async/await

    function thisTakes2Seconds() {
      return new Promise(resolve => setTimeout(() => resolve(3), 200)); // 0.2 to avoid waiting :P
    }
    
    function thisTakes5Seconds() {
      return new Promise(resolve => setTimeout(() => resolve(5), 500));
    }
    
    async function foo() {
      const data = {};
      
      data.x = await thisTakes2Seconds();
      data.y = await thisTakes5Seconds();
      
      // This will run once both promises have been resolved
      console.log(data);
    }
    
    foo()
      .then(() => console.log('done!')
      .catch(err => console.error(err));

    如果希望并行执行这两个函数,可以这样做,并等待两者都完成使用 Promise.all

    async function foo() {
      const data = {};
    
      // Promise.all returns an array where each item is the resolved
      // value of the promises passed to it, maintaining the order
      // So we use destructuring to assign those values
      [data.x, data.y] = await Promise.all([
        thisTakes2Seconds(),
        thisTakes5Seconds()
      ]);
    
      console.log(data);
    }
    

    如果您已经有了一个使用回调的异步函数,您可以很容易地将其转换为承诺。

    function myAsyncFunction(callback) {
        setTimeout(() => {
            callback(Math.random());
        }, 200);
    }
    
    function myAsyncFunctionPromise() {
         return new Promise((resolve, reject) => {
             myAsyncFunction(resolve);
             // If there is an error callback, just pass reject too.
         });
    }
    

    像Bluebird这样的库已经有了一个实用方法来支持回调API。

    http://bluebirdjs.com/docs/api/promise.promisify.html


    如果你在浏览器上运行它,并且需要支持过时的,你可以使用babel来实现 异步/等待 对ES5

        2
  •  1
  •   T.J. Crowder    8 年前

    你的 thisTakesXSeconds 函数立即返回结果。这说明它们是同步的。不需要回调,该代码只需要大约7秒即可运行。


    如果 这需要秒 开始了一个 异步 过程耗时X秒(尽管事实上 返回 结果表明不然),我们将研究如何管理完成过程。

    我真的应该有嵌套回调函数吗?

    这个问题,以及对答案“是”的普遍不满,就是为什么我们现在有了承诺,甚至 async 功能。-)

    你会让你 这需要秒 函数返回一个承诺,如果函数可以并行运行,则沿着这些行执行一些操作:

    Promise.all([
        thisTakes2Seconds(),
        thisTakes5Seconds()
    ])
    .then(([x, y]) => {
        data.x = x;
        data.y = y;
        // use or return `data` here
    })
    // return the promise or add a `catch` handler
    

    如果他们需要连续运行(一个接一个),那么

    thisTakes2Seconds()
        .then(x => {
            data.x = x;
            return thisTakes5Seconds();
        })
        .then(y => {
            data.y = y;
            // use or return `data` here
        })
        // return the promise or add a `catch` handler
    

    …在一个 异步的 功能:

    data.x = await thisTakes2Seconds();
    data.y = await thisTakes5Seconds();
    // use or return `data` here
    // add appropriate error handling (at this level or when calling the function)
    
        3
  •  0
  •   Nathan Hinchey    8 年前

    在执行了几个异步调用之后,我用来处理执行某些代码的一种技术是使用“has completed”计数器或对象。

    每个函数执行一个回调,其中包括

    if (counter == numberOfFuntionsIWantedToComplete) 
        doTheAfterWeHaveAllDataThing`