多个功能完成后运行回调

时间:2018-05-25 15:52:30

标签: javascript callback

我有多个耗时的功能,我希望在完成所有功能后运行一个功能,例如:

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

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

3 个答案:

答案 0 :(得分:1)

为了轻松处理异步函数,最好的方法是使用promisesasync/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);
}

如果你已经有一个使用回调的异步功能,你可以轻松地将其转换为promises。

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将async/await转换为ES5

答案 1 :(得分:1)

您的thisTakesXSeconds函数会立即返回结果。这告诉我们他们是同步的。无需回调,代码只需约7秒即可运行。

如果 thisTakesXSeconds启动异步进程需要X秒(尽管事实上你返回结果显示否则),我们将研究管理完成过程的方法。

  

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

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

如果函数可以并行运行,那么你的thisTakesXSeconds函数会返回一个承诺,然后沿着这些行做一些事情:

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

...在async函数中看起来更清晰:

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)

答案 2 :(得分:0)

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

每个函数都执行包含

的回调
if (counter == numberOfFuntionsIWantedToComplete) 
    doTheAfterWeHaveAllDataThing`