Запустить обратный вызов после завершения нескольких функций - PullRequest
0 голосов
/ 25 мая 2018

У меня есть несколько функций, отнимающих много времени, и я хочу запустить функцию после того, как они все завершены, например:

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

Я знаком с концепцией обратных вызовов в Javascript, но еслиУ меня есть несколько функций, я действительно должен иметь вложенные обратные вызовы с несколькими функциями?

Ответы [ 3 ]

0 голосов
/ 25 мая 2018

Одна из техник, которые я использовал для обработки выполнения некоторого кода после выполнения нескольких асинхронных вызовов, - это использование счетчика или объекта «завершен».

Каждая функция выполняет обратный вызов, включающий

if (counter == numberOfFuntionsIWantedToComplete) 
    doTheAfterWeHaveAllDataThing`
0 голосов
/ 25 мая 2018

Ваши thisTakesXSeconds функции немедленно возвращают свои результаты.Это говорит нам о том, что они синхронны.Нет необходимости в обратных вызовах, для выполнения этого кода потребуется ~ 7 секунд.


Если thisTakesXSeconds запустил асинхронный процесс , который занял X секунд (хотя тот факт, что вы возвращаете результат предполагает иное), мы рассмотрим способы управления процессом завершения.

действительно ли я должен иметь вложенные обратные вызовы нескольких функцийdeep?

Этот вопрос и общая неудовлетворенность ответом "да" - вот почему у нас теперь есть обещания и даже 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)
0 голосов
/ 25 мая 2018

Для удобной работы с асинхронными функциями лучше всего использовать 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 для переноса async/await в ES5

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...