2009-05-30 2 views
8

Если у меня есть выбор ajax для извлечения (с обратным вызовом), а затем еще какой-то другой код, выполняемый в то же время. Как я могу получить третью функцию, которая будет вызываться, когда выполняются обе первые 2. Я уверен, что с опросом легко (setTimeout, а затем проверить некоторые переменные), но я бы предпочел обратный вызов.Присоединяйтесь к 2-мя «нитям» в javascript

Возможно ли это?

ответ

14

Вы могли бы просто дать тот же обратный вызов как ваш вызов AJAX и ваш другой код, работающий в то же время, использовать переменный для отслеживания их комбинированного прогресса, затем связать их с обратным вызовом, как показано ниже:

// Each time you start a call, increment this by one 
var counter = 0; 

var callback = function() { 
    counter--; 
    if (counter == 0) { 
     // Execute code you wanted to do once both threads are finished. 
    } 
} 
+0

Поскольку нет никакой реальной многопоточности в JS (пока) это также безопасно. – Jabe

+0

Проблема в том, что один из «потоков» на самом деле не закончен, когда он вызывает функцию callback() из своего контекста. – Thevs

+0

Thevs: Именно поэтому есть счетчик, так что он продолжает выполнение только после того, как закончились оба потока. Обратите внимание, что это не полный ответ и целенаправленно; Я предполагаю некоторый интеллект со стороны искателя, так что они могут заполнить пробелы, но они необходимы. Я просто пытаюсь дать основную идею о том, как решить эту проблему. –

4

Решение Даниэля является правильным. Я взял его и добавил немного кода, так что вы не должны думать слишком много;)

function createNotifier() { 
    var counter = 2; 
    return function() { 
     if (--counter == 0) { 
      // do stuff 
     } 
    }; 
} 

var notify = createNotifier(); 
var later = function() { 
    var done = false; 
    // do stuff and set done to true if you're done 
    if (done) { 
     notify(); 
    } 
}; 

function doAjaxCall(notify) { 
    var ajaxCallback = function() { 
     // Respond to the AJAX callback here 
     // Notify that the Ajax callback is done 
     notify(); 
    }; 
    // Here you perform the AJAX call action 
} 

setInterval(later, 200); 
doAjaxCall(notify); 
0

Что-то вроде этого (схематичное):

registerThread() { 
    counter++; 
} 

unregisterThread() { 
    if (--counter == 0) fireEvent('some_user_event'); 
} 

eventHandler_for_some_user_event() { 
    do_stuff(); 
} 
3

Лучший подход к этому, чтобы воспользоваться о том, что функции являются объектами первого порядка в JavaScript. Поэтому вы можете назначить их переменным и вызывать их через переменную, изменяя функцию, к которой ссылается переменная по мере необходимости.

Например:

function firstCallback() { 
    // the first thing has happened 
    // so when the next thing happens, we want to do stuff 
    callback = secondCallback; 
} 

function secondCallback() { 
    // do stuff now both things have happened 
} 

var callback = firstCallback; 

Если обе ваши части кода теперь использовать переменную для вызова функции:

callback(); 

, то в зависимости от того один выполняет первый будет вызывать firstCallback, который изменяет переменную чтобы указать на secondCallback, и так будет вызываться в зависимости от того, что выполняет второй.

Однако ваша формулировка вопроса подразумевает, что это может быть ненужным, так как кажется, что вы делаете запрос Ajax, а затем продолжаете обработку. Поскольку интерпретаторы JavaScript являются однопоточными, обратный вызов Ajax никогда не будет выполняться до тех пор, пока основной код кода, который сделал запрос завершенным исполнением, в любом случае, даже если это происходит после получения ответа.

В случае, если это не ваша ситуация, я создал working example on my site; просмотрите источник, чтобы увидеть код (непосредственно перед тегом </body >). Он выполняет запрос, который задерживается сервером на пару секунд, а затем запрос, который получает немедленный ответ. Ответ второго запроса обрабатывается одной функцией, и ответ первого запроса позже обрабатывается другой функцией, так как запрос, который получил ответ, сначала изменил переменную обратного вызова, чтобы ссылаться на вторую функцию.

+0

Как насчет гонки, чтобы ввести firstCallback из двух потоков? –

0

Вы можете сделать это легко с помощью Google, Closure library, в частности goog.async.Deferred:

// Deferred is a container for an incomplete computation. 
var ajaxFinished = goog.async.Deferred(); 

// ajaxCall is the asynchronous function we're calling. 
ajaxCall(//args..., 
    function() { // callback 
     // Process the results... 
     ajaxFinished.callback(); // Signal completion 
    } 
); 

// Do other stuff... 

// Wait for the callback completion before proceeding 
goog.async.when(ajaxFinished, function() { 
    // Do the rest of the stuff... 
}); 

Вы можете присоединиться несколько асинхронных вычислений с использованием awaitDeferred, chainDeferred или goog.async.DeferredList.

3

Вы говорите о вещи, отложенной в javascript как @Chris Conway, упомянутой выше. Аналогично, jQuery также имеет отсрочку с v1.5.

Проверить эти Deferred.when() или deferred.done()

Не забудьте проверить JQuery документ.

Но, чтобы дать вам некоторое представление, вот что я копирую с этого сайта.

$.when($.ajax("/page1.php"), $.ajax("/page2.php")).done(function(a1, a2){ 
    /* a1 and a2 are arguments resolved for the 
     page1 and page2 ajax requests, respectively */ 
    var jqXHR = a1[2]; /* arguments are [ "success", statusText, jqXHR ] */ 
    if (/Whip It/.test(jqXHR.responseText)) { 
     alert("First page has 'Whip It' somewhere."); 
    } 
}); 

// Использование deferred.then()

$.when($.ajax("/page1.php"), $.ajax("/page2.php")) 
.then(myFunc, myFailure); 
+0

Код в вашем примере немного грязный, но это приятное решение. –

+0

Для дальнейших экспериментов я нашел этот учебник хорошим (отложенный, обещающий, труба) (http://joseoncode.com/2011/09/26/a-walkthrough-jquery-deferred-and-promise/) –

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