2012-03-29 8 views
2

Я немного запутался, как определить, когда функция асинхронной вызывается несколько раз из другого завершения вызова из последней итерации:JQuery JavaScript Уплотненный Асинхронные функции обратного вызова

function MainAsyncFunction(callback) { 
    for (var i = 0; i < 10; i++) { 
    SubAsyncFunction(function(success) { 
     if (i >= 10 && success) { // THIS IS WRONG?! 
     callback(true); // happens too early 
     } 
    }); 
    } 
}; 

function SubAsyncFunction(callback) { 
    SubSubAsyncFunction(function() { 
     callback(true); 
    }); 
} 

Что я делаю призывающего Google Distance Matrix service, который имеет ограничение в 25 пунктов назначения, поэтому мне нужно разделить мой массив пунктов назначения, чтобы называть эту услугу несколько раз, но я не понимаю, когда она будет завершена.

и в главном бите кода я могу сказать, что вторая итерация цикла в MainAsyncFunction еще не завершена, когда она перезвонила.

Я думаю, что моя проблема в том, что у меня не было головы вокруг порядка событий при работе с функциями Async в JavaScript ... пожалуйста, объясните, как обычно достигается предмет.

ответ

7

Вы можете использовать объект jQuery Deferred, который действует как токен, представляющий состояние операции async.

Ниже приведен упрощенный пример:

//set up your sub method so that it returns a Deferred object 
function doSomethingAsync() { 
    var token = $.Deferred(); 
    myAsyncMethodThatTakesACallback(function() { 
     //resolve the token once the async operation is complete 
     token.resolve(); 
    }); 
    return token.promise(); 
}; 

//then keep a record of the tokens from the main function 
function doSomethingAfterAllSubTasks() { 
    var tokens = []; 
    for (var i=0; i < 100; i++) { 
     //store all the returned tokens 
     tokens.push(doSomethingAsync()); 
    } 

    $.when.apply($,tokens) 
     .then(function() { 
      //once ALL the sub operations are completed, this callback will be invoked 
      alert("all async calls completed"); 
     }); 
}; 

Ниже приводится обновленная версия обновленного кода OP в:

function MainAsyncFunction(callback) { 
    var subFunctionTokens = []; 
    for (var i = 0; i < 10; i++) { 
    subFunctionTokens.push(SubAsyncFunction()); 
    } 

    $.when.apply($,subFunctionTokens) 
    .then(function() { 
    callback(true); 
    }); 
}; 

function SubAsyncFunction() { 
    var token = $.Deferred(); 
    SubSubAsyncFunction(function() { 
     token.resolve(); 
    }); 
    return token.promise(); 
};​ 
+0

я упростил свой код, что это по-прежнему работать для меня? – Tsar

+0

Да, это все равно будет работать. Дайте мне мгновение, и я преобразую ваш новый код ... –

+0

@Tsar см. Мое редактирование –

0

Возможно, ajaxStop() event? Это событие jQuery, которое запускается только при завершении всех активных запросов AJAX.

0

Проблема в том, что значение i постоянно меняется в цикл, окончательно выходящий за пределы после неудачного завершения цикла.

Самый простой способ исправить это:

for(i=0; i<5; i++) { // or whatever your loop is 
    (function(i) { 
     // the value of i is now "anchored" in this block. 
    })(i); 
} 
+0

Или используйте '$ .each (данные, функция (индекс, элемент) {...})' –

+0

Если вы хотите раздуть код еще несколькими сотнями команд без уважительной причины, обязательно, выбивайте себя ... –

+0

Предполагая, что вы имеете в виду jQuery, OP уже использует его (он включен в тег), поэтому он получает «каждый» бесплатно, и я лично считаю его более читаемым. Точка, принятая, хотя –

Смежные вопросы