2014-02-03 2 views
77

У меня есть две функции JS. Один называет другого. В пределах вызывающей функции я хотел бы позвонить другому, дождаться завершения этой функции, а затем продолжить. Так, например, кода/псевдо:Правильный способ дождаться завершения одной функции перед продолжением?

function firstFunction(){ 
    for(i=0;i<x;i++){ 
     // do something 
    } 
}; 

function secondFunction(){ 
    firstFunction() 
    // now wait for firstFunction to finish... 
    // do something else 
}; 

Я пришел к этому решению, но не знаю, если это умный способ пойти об этом.

var isPaused = false; 

function firstFunction(){ 
    isPaused = true; 
    for(i=0;i<x;i++){ 
     // do something 
    } 
    isPaused = false; 
}; 

function secondFunction(){ 
    firstFunction() 
    function waitForIt(){ 
     if (isPaused) { 
      setTimeout(function(){waitForIt()},100); 
     } else { 
      // go do that thing 
     }; 
    } 
}; 

Это действительно? Есть ли более элегантный способ справиться с этим? Возможно, с jQuery?

+8

Что делает 'firstFunction' именно так, что делает его асинхронным? В любом случае - проверка обещаний – zerkms

+0

Первая функция - быстрое обновление счетных очков каждые 10 секунд. Что ... подумать об этом, я думаю, мы могли бы предварительно вычислить, а затем просто вручную приостановить второй вызов функции через setTimeout. Тем не менее, я все еще вижу желание иметь возможность паузы в другом месте. –

+0

вам не нужна пауза - google для обещаний в jquery – zerkms

ответ

78

Один из способов справиться с асинхронной работой, как это использовать функцию обратного вызова, например:

function firstFunction(_callback){ 
    // do some asynchronous work 
    // and when the asynchronous stuff is complete 
    _callback();  
} 

function secondFunction(){ 
    // call first function and pass in a callback function which 
    // first function runs when it has completed 
    firstFunction(function() { 
     console.log('huzzah, I\'m done!'); 
    });  
} 

По предложению @Janaka Pushpakumara, теперь вы можете использовать функции со стрелками, чтобы достичь того же , Например:

firstFunction(() => console.log('huzzah, I\'m done!'))

+6

@zerkms - Уточните? –

+4

обратные вызовы неудобны для работы с асинхронностью, обещания намного проще и гибче – zerkms

+1

Хотя вы правы, что я не должен был использовать слово «лучше» (обновлено), удобство обратных вызовов и обещаний зависит от сложности проблемы. –

33

Это кажется вам не хватает важный момент здесь: JavaScript является однопоточной средой исполнения. Давайте снова посмотрим на код, обратите внимание, я добавил alert("Here"):

var isPaused = false; 

function firstFunction(){ 
    isPaused = true; 
    for(i=0;i<x;i++){ 
     // do something 
    } 
    isPaused = false; 
}; 

function secondFunction(){ 
    firstFunction() 

    alert("Here"); 

    function waitForIt(){ 
     if (isPaused) { 
      setTimeout(function(){waitForIt()},100); 
     } else { 
      // go do that thing 
     }; 
    } 
}; 

Вам не нужно ждать isPaused. Когда вы увидите предупреждение «Здесь», isPaused будет уже false, и firstFunction вернется. Это потому, что вы не можете «уступить» изнутри цикла for (// do something), цикл не может быть прерван и должен быть полностью завершен первым (подробнее: Javascript thread-handling and race-conditions).

Тем не менее, вы все равно можете сделать поток кода внутри firstFunction асинхронным и использовать либо обратный вызов, либо обещание уведомить вызывающего абонента. Вы должны были бы отказаться от for цикла и его имитации с if вместо (JSFiddle):

function firstFunction() 
{ 
    var deferred = $.Deferred(); 

    var i = 0; 
    var nextStep = function() { 
     if (i<10) { 
      // Do something 
      printOutput("Step: " + i); 
      i++; 
      setTimeout(nextStep, 500); 
     } 
     else { 
      deferred.resolve(i); 
     } 
    } 
    nextStep(); 
    return deferred.promise(); 
} 

function secondFunction() 
{ 
    var promise = firstFunction(); 
    promise.then(function(result) { 
     printOutput("Result: " + result); 
    }); 
} 

На стороне записки, JavaScript 1.7 представила yield ключевое слово как часть generators. Это позволит «пробивать» асинхронные дыры в обратном синхронном потоке кода JavaScript (more details and an example). Однако поддержка браузеров для генераторов в настоящее время ограничена Firefox и Chrome, AFAIK.

+2

Ты спас меня. $ .Deferred() - это то, за что я стрелял. благодаря – Temitayo

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