Статьи

JQuery Отложено


Каждый раз, когда я забываю, почему мне нравится jQuery, они постоянно напоминают мне.

Не так давно я наткнулся на
jQuery deferred (хотя он был добавлен уже в JQuery 1.5), и он мне сразу понравился. Я чувствую, что эта функция приближает разработку веб-приложений к разработке для настольных компьютеров.

Отсрочка просто позволяет добавить несколько обратных вызовов к длительным вызовам операций, таким как запросы Ajax.

Длительные операции без JQuery Deferred
Если вы не использовали deferreds, возможно, именно так вы и выполняли длительные действия, такие как вызовы ajax.

$.get("/myservice/x/1",function(data,status){alert ('example')})

Для длительных операций, таких как ajax, требуется функция обратного вызова.
В этом случае обратный вызов предоставляется в качестве параметра вызывающей стороне.

Это нормально, но есть способ добавить обратный вызов отдельно от вызова.

var myPromise = $.get("/myservice/x/1");

myPromise.done(function(data,status){alert ('ok')})
myPromise.fail(function(data,status){alert ('failed')})

Попробуй

На самом деле это самый простой пример использования Deferreds.
Методы JQuery ajax (get, post, ajax…) возвращают объект, к которому можно добавить методы обратного вызова.

Почему лучше?
Просто потому, что это позволяет вам отделить логику выполнения и логику результата. Это делает код более читабельным и понятным.

Так что же такое «Отложенный»?
Deferred — это объект, который позволяет вам добавить несколько методов обратного вызова.
Это также вызывает события, которые определяют состояние вызова, используя его, чтобы определить, какие методы обратного вызова будут вызваны.

В приведенном выше примере Ajax 2 обратных вызова — «выполнено» и «не выполнено», которые запускаются в соответствии с состоянием вызова Ajax.

Этот список показывает, какие события будут вызывать какие обратные вызовы.

Обратные звонки События →
 ↓
deferred.always () deferred.done () deferred.fail () deferred.progress ()
deferred.notify ()       Срабатывает
deferred.notifyWith ()       Срабатывает
deferred.reject () Срабатывает   Срабатывает  
deferred.rejectWith () Срабатывает   Срабатывает  
deferred.resolve () Срабатывает Срабатывает    
deferred.resolveWith () Срабатывает Срабатывает    

Что такое «Обещание»?
Обещание — это объект, который передается от Отложенного и может использоваться только для добавления обратных вызовов.

Два объекта, Отложенный и Обещающий, дают нам разделение в логике вызывающей стороны и логике результата.

Например, в вызовах ajax JQuery вызов ajax создает Deferred, а также Promise из этого Deferred. Отложенный используется для запуска событий, и Обещание возвращается пользователю, поэтому он добавляет к нему функции обратного вызова.

Создание собственных функций Deferreds
Вы также можете использовать Deferreds в своей функции так же, как их используют функции ajax.

Это шаги:
1. Создайте Deffered внутри вашей функции.
2. Используйте Deffered для запуска событий.
3. Верните объект Promise.

Посмотрите на этот простой пример:

myLongLastingOperation = function(time) {
  var myDeferred = $.Deferred();
  setTimeout(myDeferred.resolve, time);
  return myDeferred.promise();
}

myPromise = myLongLastingOperation(1000);
myPromise.done(function(){alert('ok')})
myPromise.fail(function(){alert('failed')})

Попробуй

В приведенном выше примере я создал функцию, похожую на то, что делает функция ajax.
Я создал Deferred, использовал Deferred для запуска события с помощью функции resovle () после завершения операции и возвратил обещание, которое я создал из этого Deferred.
Возвращенное обещание затем используется для добавления обратных вызовов.

Progress
resol () и reject () — это события, которые определяют состояние результата операции.
Но есть другое событие, которое вы можете вызвать — notify ().
Это событие, которое было добавлено в версии 1.7, может быть вызвано, если у вас есть процесс, и вы хотите вызвать обратный вызов, пока процесс еще выполняется.

myLongLastingOperation = function(time,numOfCount) {
 var  myDeferred = $.Deferred();
   
   function wait(counter){
        if(counter<numOfCount){
            myDeferred.notify();
            setTimeout(function(){wait(counter+1)}, time);   
        }   
        else{
             myDeferred.resolve();
        }
    }
   wait(0); 
  return myDeferred.promise();
}

myPromise = myLongLastingOperation(100, 3);
myPromise.progress(function(){document.write('tick')});
myPromise.done(function(){document.write('done')});

Попробуй

Еще не впечатлило? Встречайте «когда»
Мы увидели, что вы можете добавить несколько обратных вызовов к Отложенным и Обещаниям.
«когда» позволяет вам делать то же самое, но может делать это одновременно для нескольких отложенных.

myLongLastingOperation = function(time) {
 var  myDeferred = $.Deferred();
 setTimeout(function(){myDeferred.resolve();}, time);
 return myDeferred.promise();
}
myPromise = $.when( 
    myLongLastingOperation(500),
    myLongLastingOperation(1700));

myPromise.done(function(){document.write('done')});

Попробуй

В этом случае обратный вызов done будет запущен только после разрешения двух процессов.
Это дает вам возможность синхронизировать многие длительные процессы, которые могут быть полезны для многих вещей.
Например, если вы загружаете много источников, и вы хотите что-то сделать, когда все они сделаны.

Изменяя результат на «затем»,
я упомянул, что вы не можете запускать события в Обещании, вы можете только добавлять события в Обещание.
Тем не менее, у вас все еще есть способ контролировать результат другим способом; добавив фильтры в Promise, которые смогут изменить ответ от звонящего.
Так как JQuery 1.8 это делается с помощью « затем команды»:

var myPromise = $.get('non_exiting.php');

myPromise = myPromise.then(
    function(){return $.Deferred().resolve("ok")},
    function(){return $.Deferred().resolve("ajax failed but still we pass")});

myPromise.done(function(message){document.write('done: '+message);});
myPromise.fail(function(message){document.write('error: '+message);});

Попробуй

В этом примере показано, что, хотя deferred (ajax) завершился неудачно, фильтр изменил результат для разрешения, в результате чего вместо «fail» сработал обратный вызов «done».
Обратите внимание, что «then» также возвращает обещание, что делает его командой с возможностью цепочки, что означает, что вы можете объединять несколько фильтров один за другим.

* Обратите внимание , до версии 1.8 вы делали это, используя

труба
команда, но начиная с 1.8 это делается с помощью ‘ then ‘.
«Затем» был первоначально добавлен в версии 1.5 в качестве обратного вызова, который запускается при каждом событии.
Но начиная с версии 1.8 он изменил свою цель, чтобы стать цепным методом фильтрации, который может влиять на состояние результата.
Вот почему вы все еще можете увидеть примеры в Интернете, которые делают это по-старому.

Добавление обратных вызовов после того, как событие было инициировано.
Вы должны знать, что вы можете добавить функции обратного вызова в обещание, даже если Отложенное уже было разрешено или не выполнено.
Это означает, что если вы добавите метод обратного вызова, например, к вызову ajax, который уже был возвращен, обратный вызов будет немедленно запущен.

Эта небольшая и, казалось бы, неважная функция на самом деле весьма полезна, потому что вам не нужно беспокоиться о том, что Deferred завершается при добавлении обратных вызовов. Более того, он позволяет вам добавлять множество обратных вызовов в любое время и, таким образом, повторно использовать отложенные.
Хорошим примером для такого использования может служить кеш вызовов ajax, что я довольно успешно реализовал на своем рабочем месте ( convertro.com ).