Önceki işlev tamamlandıktan sonra bir işlevi çağırma


179

Aşağıdaki JavaScript koduna sahibim:

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable);
        function2(someOtherVariable);
    }
    else {
        doThis(someVariable);
    }
});

function2Sadece aramanın function1tamamlanmasının ardından nasıl çağrılabilirim ?


24
zaman function1uyumsuz işlem gerçekleştiriyor mu?
LiraNuna

8
Yads, işlev1 animasyon içeriyorsa, işlev1'in animasyonları devam ederken işlev2 yürütülür. Function2'de başlayan her şey tamamen bitene kadar function2'yi nasıl bekletirsiniz?
trusktr

Birisi bana, function1 tamamlanana kadar function2'nin çağrılmadığından emin olmak için neden yapılması gereken bir şey olduğunu açıklayabilir mi? Burada eşzamansız bir işlem yoktur, bu nedenle işlev1, bu işlem eşzamanlı olduğu için işlev1 tamamlanana kadar işlev2 çalışmaz.
Aaron

Yanıtlar:


206

Anonim bir geri arama belirtin ve işlev1'in kabul etmesini sağlayın:

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable, function() {
          function2(someOtherVariable);
        });
    }
    else {
        doThis(someVariable);
    }
});


function function1(param, callback) {
  ...do stuff
  callback();
} 

11
+1 ama 1.5 kullanıyorsa, yeni Deferreds desenini kullanabilir
philwinkle

Hızlı yanıt (lar) için teşekkürler. Evet, function1 sadece basit bir eşzamansız görev gerçekleştiriyor, bu yüzden bir geri arama oluşturmak zorunda kalacağım konusunda doğru olduğuna inanıyorum - ya da philwinkle'ın bahsettiği bu ertelenmiş işlere bir göz atın. Tekrar teşekkürler çocuklar. Biraz uyuyacağım ve sabah tekrar bununla başa çıkacağım.
Rrryyyaaannn

13
Bu cevap çözüm değil. İşte işe yaramadığına dair kanıt: jsfiddle.net/trusktr/M2h6e
trusktr

12
@MikeRobinson Sorun şu: Ya ...do stuffzaman uyumsuz şeyler içeriyorsa? İşlev2 beklendiğinde hala çalışmaz. Çünkü gösterileri yukarıda benim yorumunda örnek foo()işlevi içinde asenkron kodu vardır, bar()sonra 's içeriğini patlamaz foo()bireyin içerik yürütme yapılır, hatta kullanılarak $.when().then()peş peşe onları aramak için. Bu yanıt yalnızca ...do stuffkodunuzdaki tüm öğeler tamamen senkronize olduğunda (ve yalnızca) geçerlidir .
trusktr

1
@trusktr Bu durumda aşağı ilk geri arama geçen tutmak için gereken n asenkron çağrı inci seviyede, daha sonra yangın callBack()sonuçta n asenkron çağrılar yapılmaktadır. OP işlevde ne yaptığından bahsetmediği için, onu bir seviye asenkron çağrı olarak kabul etti.
GoodSp33d

96

JQuery 1.5 kullanıyorsanız, yeni Ertelenmişler desenini kullanabilirsiniz:

$('a.button').click(function(){
    if(condition == 'true'){
        $.when(function1()).then(function2());
    }
    else {
        doThis(someVariable);
    }
});

Düzenle: Güncellenmiş blog bağlantısı:

Rebecca Murphy burada harika bir yazı yazdı: http://rmurphey.com/blog/2010/12/25/deferreds-coming-to-jquery/


2
Ama bu çalışan bir örnek mi? Ertelenenler nelerdir? İşlev1 ve işlev2'yi hemen yürütüyorsunuz. (Ben orijinal yorumcu değilim.)
user113716 15:11

10
Bu benim için hiç işe yaramıyor. function1 ve function2 her ikisi de aynı anda yürütülür (insan gözünün gözlemleyebileceği gibi). İşte size küçük bir örnek: jsfiddle.net/trusktr/M2h6e
trusktr

1
Rebecca Murphy'nin yazımı Defferds'ın jQuery ile tanışmasından önceydi ve yazarın nasıl uygulanacağını düşündüğüne göre örnekler kullanıyor. Bu özelliğin nasıl kullanılacağını görmek için lütfen jQuery sitesini ziyaret edin: api.jquery.com/jQuery.Deferred
Spencer Williams

1
JQuery 1.5 veya modern bir şeyle bile $.when(function1).then(function2);(işlevi çağıran parantezler olmadan) istemiyor musunuz?
Teepeemm

1
Birkaç yıl sonra bu yorumları okumak. function1bir söz vermeli. Bu durumda, başvuru değil gerçek yürütülen işlev olması gerekir. Bu resolvesöz üzerine çağrıldığında function2yürütülür. Bu durum,function1 bir ajax çağrısı . Geri donearama daha sonra vaadi çözecektir. Umarım bu açıktır.
philwinkle

46

Bunu dene :

function method1(){
   // some code

}

function method2(){
   // some code
}

$.ajax({
   url:method1(),
   success:function(){
   method2();
}
})

37

Bu cevap promises, ECMAScript 6standardın JavaScript özelliğini kullanır . Hedef platformunuz desteklemiyorsapromises PromiseJs ile çoklu doldurun .

Vaatler, JavaScript'te eşzamansız işlemleri gerçekleştirmenin yeni (ve çok daha iyi) bir yoludur:

$('a.button').click(function(){
    if (condition == 'true'){
        function1(someVariable).then(function() {
            //this function is executed after function1
            function2(someOtherVariable);
        });
    }
    else {
        doThis(someVariable);
    }
});


function function1(param, callback) {
    return new Promise(function (fulfill, reject){
        //do stuff
        fulfill(result); //if the action succeeded
        reject(error); //if the action did not succeed
    });
} 

Bu, bu basit örnek için önemli bir ek yük gibi görünebilir, ancak daha karmaşık kodlar için geri arama kullanmaktan çok daha iyidir. Birden çok thenifadeyi kullanarak birden çok eşzamansız çağrıyı kolayca zincirleyebilirsiniz :

function1(someVariable).then(function() {
    function2(someOtherVariable);
}).then(function() {
    function3();
});

Ayrıca jQuery ertelemelerini kolayca ( $.ajaxaramalardan döndürülen ) sarabilirsiniz :

Promise.resolve($.ajax(...params...)).then(function(result) {
    //whatever you want to do after the request
});

@Charlietfl'in belirttiği gibi, jqXHRdöndürülen nesne arabirimi $.ajax()uygular Promise. Bu yüzden bir a sarmak gerekli değildir Promise, doğrudan kullanılabilir:

$.ajax(...params...).then(function(result) {
    //whatever you want to do after the request
});

Promise.resolvethennable vaat döner $.ajaxçünkü sarma anti-desen$.ajax
charlietfl

@charlietfl ama gerçek değil Promise, sadece arayüzü uygular. Bir gerçek geçerken davrandığını emin nasıl değilim Promiseonun için thenyöntemin, ya da ne bir Promise.allbir yapardınız jqXHRve Promisekendisine geçirilir. Bunun için daha fazla test yapmam gerekiyor. Ama ipucu için teşekkür ederim, cevaba ekleyeceğim!
Domysee

Aslında jQuery sürüm 3+ Promises A + uyumludur. Saygısız $.ajax.thendeğil yeni
charlietfl

21

Veya bir işlev tamamlandığında özel bir etkinliği tetikleyebilir, ardından bunu belgeye bağlayabilirsiniz:

function a() {
    // first function code here
    $(document).trigger('function_a_complete');
}

function b() {
    // second function code here
}

$(document).bind('function_a_complete', b);

Bu yöntemi kullanarak, 'b' işlevi yalnızca 'a' işlevinden SONRA yürütebilir, çünkü tetikleyici yalnızca işlev a yürütme tamamlandığında vardır.


"JQuery 1.7'den itibaren .on () yöntemi, olay işleyicilerini bir belgeye eklemek için tercih edilen yöntemdir." api.jquery.com/bind
CodeVirtuoso


3

Bu, function1'in ne yaptığına bağlıdır.

Function1, div değerini veya başka bir şeyi güncellemek gibi basit bir senkronize javascript yapıyorsa, function1 tamamlandıktan sonra function2 tetiklenir.

Function1, AJAX çağrısı gibi eşzamansız bir çağrı yapıyorsa, bir "geri çağrı" yöntemi oluşturmanız gerekir (ajax API'lerinin çoğunda geri çağrı işlevi parametresi bulunur). Ardından geri aramada function2'yi çağırın. Örneğin:

function1()
{
  new AjaxCall(ajaxOptions, MyCallback);
}

function MyCallback(result)
{
  function2(result);
}

2

Yöntem 1, yöntem 2, 3, 4'ten sonra yürütülecekse, aşağıdaki kod snippet'i JavaScript'te Ertelenmiş nesne kullanılarak çözüm olabilir.

function method1(){
  var dfd = new $.Deferred();
     setTimeout(function(){
     console.log("Inside Method - 1"); 
     method2(dfd);	 
    }, 5000);
  return dfd.promise();
}

function method2(dfd){
  setTimeout(function(){
   console.log("Inside Method - 2"); 
   method3(dfd);	
  }, 3000);
}

function method3(dfd){
  setTimeout(function(){
   console.log("Inside Method - 3"); 	
   dfd.resolve();
  }, 3000);
}

function method4(){   
   console.log("Inside Method - 4"); 	
}

var call = method1();

$.when(call).then(function(cb){
  method4();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>


0

Function1, zaman uyumsuz bir işleve dönüştürmek istediğiniz bazı senkronizasyon işleviyse, tamamlanması biraz zaman alır ve geri arama eklemek için üzerinde kontrolünüz olmaz:

function function1 (someVariable) {
    var date = Date.now ();
    while (Date.now () - date < 2000);      // function1 takes some time to complete
    console.log (someVariable);
}
function function2 (someVariable) {
    console.log (someVariable);
}
function onClick () {
    window.setTimeout (() => { function1 ("This is function1"); }, 0);
    window.setTimeout (() => { function2 ("This is function2"); }, 0);
    console.log ("Click handled");  // To show that the function will return before both functions are executed
}
onClick ();

Çıktı şöyle olacaktır:

Click handled

... ve 2 saniye sonra:

This is function 1
This is function 2

Bunun nedeni, window.setTimeout () öğesinin çağrılmasının, zaman uyumsuz çağrının yaptığı JS runtine görev döngüsüne bir görev ekleyeceği ve JS çalışma zamanının "çalışma-tamamlama" temel ilkesinin onClick () sona ermeden asla kesilmez.

Kodun anlaşılması zor olabileceği kadar komik olduğuna dikkat edin ...

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.