2016-07-09 16 views
0

Trotz der vielen Antworten hier zum Thema, verstehe ich immer noch nicht wirklich $.Deferred() Objekte.Wie kann ein verzögertes Objekt auf einen großen Codeblock angewendet werden?

Ich möchte sie besser verstehen und vermeiden Sie "Anti-Muster".

Ich habe gelesen:

https://api.jquery.com/category/deferred-object/

Und was „Sticks“ ist, dass es ein Objekt mit Methoden zur Verfügung, um es, wie done() ist.

Ich habe versucht, auf this answer das einfachste Beispiel möglich, basierend zu erstellen:

jsFiddle Link

function function1() { 
    // create a deferred object first 
    var dfrd1 = $.Deferred(); 

    // mimic an async request 
    setTimeout(function() { 
     // lots of async stuff here 
     // resolve the deferred object 
     dfrd1.resolve(); 
    }, 1000); 

    // return a promise() 
    return dfrd1.promise(); 
} 

function1().done(function() { 
    // when function1 is done, do something 
    console.log('function1 is done!'); 
}); 

Es scheint vier Komponenten, dies zu sein:

  • erstellen $.Deferred() Objekt.
  • resolve() es nach dem asynchronen Codeblock.
  • Geben Sie nach dem asynchronen Codeblock eine promise() zurück.
  • Rufen Sie die done() Methode.

Das obige Beispiel scheint jedoch wie erwartet zu funktionieren, wenn ich versuche, diese Logik auf eine große Funktion anzuwenden, die eine $.ajax() Anfrage enthält, um eine Klasse zu Inhalt anzuwenden, nachdem es geladen hat, ist die Klasse nicht wird benutzt.

Ich kann den Code addClass() über Firebug ausführen, also ist nichts falsch mit diesem Code.

Der Pseudo-Code für das große Funktion Szenario ist:

function largeFunction(myVar) { 

    // create a deferred object first 
    var dfrd1 = $.Deferred(); 

    // lots of code and an ajax request here 

    // resolve the object and return a promise 
    // (this seems naive to hope resolve will 
    // know when everything above has completed) 
    dfrd1.resolve(); 
    return dfrd1.promise(); 

} 

// call the done() method from an on click event 

$(document).on("click", ".some_class", function() { 

    largeFunction(myVar).done(function() { 

     console.log('largeFunction(myVar) is done, you can now add class'); 

     var my_classes = $(".my_class"); 

     $.each(classes, function(index, value) { 
      $(this).addClass("another_class"); 
     }); 

    }); 

}); 

Das Folgende ist eine gute, kurze, einfache Antwort auf eine $.Deferred() Frage, die ich die Logik zu verstehen, aber scheint nicht zu anwendbar in meinem Szenario (zB kann ich nicht nur die promise() nach einer einfachen fadeOut() Kette):

https://stackoverflow.com/a/24234881/1063287

Frage

In dem obigen Beispiel der großen Funktion, welche Konventionen muss ich befolgen, um done() aufzurufen, nachdem die Ajax-Anfrage usw. ausgeführt wurde?

+2

Einfach - lösen Sie die 'dfd' in der' then' Methode des Ajax Calls (oder geben Sie den 'ajax' Aufruf selbst zurück). – Adam

+0

@Adam oder Sie könnten das Versprechen aus dem '$ .ajax' Anruf selbst zurückgeben. In jedem Fall sollten Sie das als Antwort hinzufügen –

Antwort

1

First off, würde ich vorschlagen, dies zu ändern:

function function1() { 
    // create a deferred object first 
    var dfrd1 = $.Deferred(); 

    // mimic an async request 
    setTimeout(function() { 
     // lots of async stuff here 
     // resolve the deferred object 
     dfrd1.resolve(); 
    }, 1000); 

    // return a promise() 
    return dfrd1.promise(); 
} 

function1().done(function() { 
    // when function1 is done, do something 
    console.log('function1 is done!'); 
}); 

dazu:

function function1() { 
    // create a deferred object first 
    return $.Deferred(function(def) { 
     // mimic an async request 
     setTimeout(function() { 
      // lots of async stuff here 
      // resolve the deferred object 
      def.resolve(); 
     }, 1000); 
    }).promise(); 

} 

function1().then(function() { 
    // when function1 is done, do something 
    console.log('function1 is done!'); 
}); 

Ihr ursprünglicher Code funktioniert gut und enthält kein anti-Muster, aber dieser neue Code hat diese Vorteile :

  1. ist der Rückruf an $.Deferred() Verwendung näher an, wie das Versprechen standa ES6 rd arbeitet mit new Promise(), so ist es generell eine gute Idee, Ihre Programmierung in Richtung der Standards zu verschieben.

  2. Verwenden Sie .then() statt .done(). .then() ist, wie die ES6-Standards funktionieren und jQuery es gut unterstützt. Wenn Sie irgendwann in der Zukunft function1() geändert haben, um ein tatsächliches ES6-Versprechen anstelle von jQuery-Versprechen zu verwenden, dann würde Ihr function1().then() weiterhin gut funktionieren.


In jQuery, eine Ajax-Anfrage liefert bereits ein Versprechen. Es besteht keine Notwendigkeit, es in einen verzögerten zu verpacken, und tatsächlich ist dies ein Anti-Muster (ein Versprechen zu erstellen, wenn Sie kein neues erstellen müssen).

Versprechen haben KEINE magische Kraft, nur zu wissen, wenn asynchrone Dinge getan werden. Stattdessen muss ein Code speziell .resolve() aufrufen, wenn der asynchrone Vorgang abgeschlossen ist. Und im Fall von jQuery Ajax-Funktionen geschieht dies automatisch für Sie mit dem Versprechen, dass alle jQuery Ajax-Funktionen zurückkehren. So können Sie genau dies tun:

function largeFunction(myVar) { 

    return $.ajax(...); 

} 

largeFunction(....).then(function(results) { 
    // handle successful results here 
}, function(jqXHR, textStatus, errorThrown) { 
    // handle error here 
}); 

Wenn Sie mehrere Ajax-Funktionen oder asynchrone Operationen innerhalb largeFunction() haben, dann können Sie Versprechen Kette nutzen sie (die es ihnen sequenzieren) oder sie koordinieren und nach wie vor Rückkehr Ein einzelnes Versprechen, das darstellt, wenn alles erledigt ist und die gewünschten Endergebnisse darstellt. jQuery bietet Koordinationswerkzeuge wie $.when(), um zu wissen, wenn mehrere Versprechungen gemacht werden (dies ist Promise.all() im ES6-Standard).