284 votes

Comment peut-jQuery différés être utilisé?

jQuery 1.5 apporte le nouveau Différé d'objet et le joint méthodes d' .when, .Deferred et ._Deferred.

Pour ceux qui havn pas utilisé .Deferred avant, j'ai annoté de la source pour elle

Quelles sont les utilisations possibles de ces nouvelles méthodes, comment pouvons-nous aller sur la côté d'eux dans les modèles?

J'ai déjà lu l' API et de la source, donc je sais ce qu'il fait. Ma question est comment pouvons-nous utiliser ces nouvelles fonctionnalités dans le quotidien de code?

J'ai un simple exemple d'une classe de mémoire tampon qui appelle à une requête AJAX dans l'ordre. (Prochain démarrage après le précédent se termine).

/* Class: Buffer
 *  methods: append
 *
 *  Constructor: takes a function which will be the task handler to be called
 *
 *  .append appends a task to the buffer. Buffer will only call a task when the 
 *  previous task has finished
 */
var Buffer = function(handler) {
    var tasks = [];
    // empty resolved deferred object
    var deferred = $.when();

    // handle the next object
    function handleNextTask() {
        // if the current deferred task has resolved and there are more tasks
        if (deferred.isResolved() && tasks.length > 0) {
            // grab a task
            var task = tasks.shift();
            // set the deferred to be deferred returned from the handler
            deferred = handler(task);
            // if its not a deferred object then set it to be an empty deferred object
            if (!(deferred && deferred.promise)) {
                deferred = $.when();
            }
            // if we have tasks left then handle the next one when the current one 
            // is done.
            if (tasks.length > 0) {
                deferred.done(handleNextTask);
            }
        }
    }

    // appends a task.
    this.append = function(task) {
        // add to the array
        tasks.push(task);
        // handle the next task
        handleNextTask();
    };
};

Je suis à la recherche pour les démonstrations et les utilisations possibles de l' .Deferred et .when.

Il serait également agréable de voir des exemples de ._Deferred.

La liaison à la nouvelle - jQuery.ajax source des exemples est de la triche.

Bounty: nous Montrer quelles techniques sont disponibles lorsque nous abstraire de savoir si une opération est en mode synchrone ou asynchrone fait.

217voto

ehynds Points 2328

La meilleure façon que je peux penser à est de mettre en cache les réponses AJAX. Voici une modification de l'exemple de Rebecca Murphey l'intro de post sur le sujet:

var cache = {};

function getData( val ){

    // return either the cached value or an
    // jqXHR object (which contains a promise)
    return cache[ val ] || $.ajax('/foo/', {
        data: { value: val },
        dataType: 'json',
        success: function( resp ){
            cache[ val ] = resp;
        }
    });
}

getData('foo').then(function(resp){
    // do something with the response, which may
    // or may not have been retreived using an
    // XHR request.
});

En gros, si la valeur a déjà été demandé une fois avant d'être retourné immédiatement à partir du cache. Sinon, une requête AJAX récupère les données et l'ajoute à la cache. L' $.when/.then ne se soucie pas du tout de cela, tout ce que vous devez être préoccupé est à l'aide de la réponse, qui est transmis à l' .then() gestionnaire dans les deux cas.

Deferreds sont parfaits pour quand la tâche peut ou peut ne pas fonctionner de manière asynchrone, et que vous voulez abstraite que la condition de code.

Un autre exemple réel à l'aide de l' $.when helper:

$.when($.getJSON('/some/data/'), $.get('template.tpl')).then(function (data, tmpl) {

    $(tmpl) // create a jQuery object out of the template
    .tmpl(data) // compile it
    .appendTo("#target"); // insert it into the DOM

});

79voto

Julian D. Points 4235

Ici est un peu différente de la mise en œuvre d'un AJAX cache dans ehynd de réponse.

Comme indiqué dans fortuneRice suivi de la question, ehynd de la mise en œuvre n'a pas réellement d'éviter que plusieurs demandes identiques si les demandes ont été effectuées avant que l'un d'entre eux étaient retournés. Qui est,

for (var i=0; i<3; i++) {
    getData("xxx");
}

le plus de chances d'3 requêtes AJAX si le résultat pour "xxx" n'a pas déjà été mis en cache avant.

Ce problème peut être résolu par la mise en cache à la demande du Deferreds à la place du résultat:

var cache = {};

function getData( val ){

    // Return a promise from the cache (if available)
    // or create a new one (a jqXHR object) and store it in the cache.
    var promise = cache[val];
    if (!promise) {
        promise = $.ajax('/foo/', {
            data: { value: val },
            dataType: 'json'
        });
        cache[val] = promise;
    }
    return promise;
}

$.when(getData('foo')).then(function(resp){
    // do something with the response, which may
    // or may not have been retreived using an
    // XHR request.
});

46voto

user406905 Points 1004

Un différé peut être utilisé à la place d'un mutex. C'est essentiellement le même que les multiples ajax scénarios d'utilisation.

MUTEX

var mutex = 2;

setTimeout(function() {
 callback();
}, 800);

setTimeout(function() {
 callback();
}, 500);

function callback() {
 if (--mutex === 0) {
  //run code
 }
}

DIFFÉRÉ

function timeout(x) {
 var dfd = jQuery.Deferred();
 setTimeout(function() {
  dfd.resolve();
 }, x);
 return dfd.promise();
}

jQuery.when(
timeout(800), timeout(500)).done(function() {
 // run code
});

Lors de l'utilisation d'un Différé comme un mutex seulement, watch out pour les effets sur les performances (http://jsperf.com/deferred-vs-mutex/2). Bien que la commodité, ainsi que d'autres prestations fournies par un Différé est bien la peine, et en réel (actionné par l'utilisateur basée sur les événements) l'utilisation de l'impact de la performance ne devrait pas être perceptible.

29voto

Alex Mcp Points 6456

C'est une auto-promotion de réponse, mais j'ai passé quelques mois à la recherche de cette et a présenté les résultats à jQuery de la Conférence de San Francisco 2012.

Voici une vidéo de la conférence:

http://www.confreaks.com/videos/993-jqcon2012-i-promise-to-show-you-when-to-use-deferreds

20voto

Elf Sternberg Points 9764

Une autre utilisation que j'ai été de le mettre à bonne pour but d'extraire des données à partir de plusieurs sources. Dans l'exemple ci-dessous, je suis aller chercher de multiples, indépendants JSON objets de schéma utilisé dans une application existante pour la validation entre un client et d'un serveur. Dans ce cas, je ne veux pas le navigateur de l'application côté pour lancer le chargement des données avant qu'il dispose de tous les schémas chargé. $.lors de l'.appliquer().alors() est parfait pour cela. Merci à Raynos pour les pointeurs sur l'utilisation d'alors(fn1, fn2) afin de surveiller les conditions d'erreur.

fetch_sources = function (schema_urls) {
    var fetch_one = function (url) {
            return $.ajax({
                url: url,
                data: {},
                contentType: "application/json; charset=utf-8",
                dataType: "json",
            });
        }
    return $.map(schema_urls, fetch_one);
}

var promises = fetch_sources(data['schemas']);
$.when.apply(null, promises).then(

function () {
    var schemas = $.map(arguments, function (a) {
        return a[0]
    });
    start_application(schemas);
}, function () {
    console.log("FAIL", this, arguments);
});     

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X