Как можно использовать jQuery deferred? - PullRequest
277 голосов
/ 02 февраля 2011

jQuery 1.5 приносит новый отложенный объект и присоединенные методы .when, .Deferred и ._Deferred.

Для тех, кто не использовал .Deferred раньше, я аннотировал источник для него .

Каковы возможные применения этих новых методов, как мы можем приспособить их к шаблонам?

Я уже прочитал API и source , поэтому я знаю, что он делает. Мой вопрос: как мы можем использовать эти новые функции в повседневном коде?

У меня есть простой пример класса буфера, который вызывает AJAX-запрос по порядку. (Следующий начинается после окончания предыдущего).

/* 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();
    };
};

Я ищу демонстрации и возможные варианты использования .Deferred и .when.

Было бы также приятно увидеть примеры ._Deferred.

Ссылка на новый источник jQuery.ajax для примеров - мошенничество.

Меня особенно интересует, какие методы доступны, когда мы абстрагируемся, выполняется ли операция синхронно или асинхронно.

Ответы [ 11 ]

1 голос
/ 02 июня 2014

Я только что использовал Deferred в реальном коде. В проекте jQuery Terminal у меня есть функция exec, которая вызывает команды, определенные пользователем (например, он вводил ее и нажимал ввод), я добавил Deferreds в API и вызвал exec с массивами. как это:

terminal.exec('command').then(function() {
   terminal.echo('command finished');
});

или

terminal.exec(['command 1', 'command 2', 'command 3']).then(function() {
   terminal.echo('all commands finished');
});

команды могут запускать асинхронный код, и exec должен вызывать код пользователя по порядку. Мой первый API использует пару вызовов паузы / возобновления, и в новом API я вызываю их автоматически, когда пользователь возвращает обещание. Таким образом, пользовательский код может просто использовать

return $.get('/some/url');

или

var d = new $.Deferred();
setTimeout(function() {
    d.resolve("Hello Deferred"); // resolve value will be echoed
}, 500);
return d.promise();

Я использую такой код:

exec: function(command, silent, deferred) {
    var d;
    if ($.isArray(command)) {
        return $.when.apply($, $.map(command, function(command) {
            return self.exec(command, silent);
        }));
    }
    // both commands executed here (resume will call Term::exec)
    if (paused) {
        // delay command multiple time
        d = deferred || new $.Deferred();
        dalyed_commands.push([command, silent, d]);
        return d.promise();
    } else {
        // commands may return promise from user code
        // it will resolve exec promise when user promise
        // is resolved
        var ret = commands(command, silent, true, deferred);
        if (!ret) {
            if (deferred) {
                deferred.resolve(self);
                return deferred.promise();
            } else {
                d = new $.Deferred();
                ret = d.promise();
                ret.resolve();
            }
        }
        return ret;
    }
},

dalyed_commands используется в функции возобновления, которая снова вызывает exec со всеми dalyed_commands.

и часть функции команд (я удалил не связанные части)

function commands(command, silent, exec, deferred) {

    var position = lines.length-1;
    // Call user interpreter function
    var result = interpreter.interpreter(command, self);
    // user code can return a promise
    if (result != undefined) {
        // new API - auto pause/resume when using promises
        self.pause();
        return $.when(result).then(function(result) {
            // don't echo result if user echo something
            if (result && position === lines.length-1) {
                display_object(result);
            }
            // resolve promise from exec. This will fire
            // code if used terminal::exec('command').then
            if (deferred) {
                deferred.resolve();
            }
            self.resume();
        });
    }
    // this is old API
    // if command call pause - wait until resume
    if (paused) {
        self.bind('resume.command', function() {
            // exec with resume/pause in user code
            if (deferred) {
                deferred.resolve();
            }
            self.unbind('resume.command');
        });
    } else {
        // this should not happen
        if (deferred) {
            deferred.resolve();
        }
    }
}
...