2015-06-10 5 views
5

Не удается найти delay или wait Функция для jQuery обещания. Я нашел одну функцию на SO (Using jQuery.Deferred to avoid nested setTimeout callbacks):Задержка для обещаний jquery

function delay(time) { 
    return function() { 
     console.log("Delaying"); 
     var ret = new $.Deferred(); 
     setTimeout(function() { 
      ret.resolve(); 
     }, time); 
     return ret; 
    }; 
} 

И это так, как я использую его:

run: function() { 
     return $() 
      .promise() 
      .then(function() { 
       console.log("call together"); 
       console.log("call together");  
      }) 
      .then(delay(2000)) 
      .then(function() { 
       console.log("call first"); 
      }) 
      .then(delay(2000)) 
      .then(function() { 
       console.log("call second"); 
      }) 
    } 

Я хочу продлить обещание или отложенный объект, который я могу написать, как:

run: function() { 
      return $() 
       .promise() 
       .then(function() { 
        console.log("call together"); 
        console.log("call together");  
       }) 
       .delay(2000) 
       .then(function() { 
        console.log("call first"); 
       }) 
       .delay(2000) 
       .then(function() { 
        console.log("call second"); 
       }) 
     } 
+0

@ guest271314: Мне нужна функция именно обещаний. Эта функция для эффектов. – user348173

+0

Возможный дубликат [Можно ли добавлять методы в объект обещания JQuery?] (Http://stackoverflow.com/q/30719454/1048572) (просто добавьте метод '.delay' вместо' .catch') – Bergi

+0

@ jfriend00: Ну, конечно [возможно] (http://stackoverflow.com/a/30719727/1048572) ... но не так легко, как продлить прототип. – Bergi

ответ

3

Как @Bergi говорит JQuery Deferreds/Обещания не расширяемые по прототипному наследованию.

Вместо этого, модель, принятая JQuery, чтобы позволить отдельные случаи Promise быть расширены с помощью синтаксиса:

deferred.promise(target); 
//or, 
promise.promise(target); //(though the documentation doesn't make this clear) 
// where `target` is an "object onto which the promise methods have to be attached" 
// see https://api.jquery.com/deferred.promise/ 

Определяя конструктор с кучей методов, любой Jquery Отложенный или Promise может быть расширен простой синтаксис

.promise(Constructor()) 

в моей неопубликованной, незарегистрированные JQuery обещает Playground, конструктор называется $P и хранится в пространстве имен JQuery, следовательно, фактический синтаксис я использую:

.promise($.$P()) 

Вы должны быть осведомлены о том, что, по большей части, это не нужно вызывать $.$P() явно как площадка включает в себя $.when_() метода, который возвращает уже расширенное обещание.

Вот сокращенная версия Playground с достаточно, чтобы обеспечить .delay() метод:

(function($) { 
    /* *********************************** 
    * The $.$P function returns an object 
    * designed to be extended with 
    * promise methods using the syntax : 
    * myDeferred.promise($.$P()) 
    * myPromise.promise($.$P()) 
    * where `myDeferred`/`myPromise` 
    * are jQuery Deferred/Promise objects. 
    * ***********************************/ 

    /* *********************************** 
    * Methods 
    * ***********************************/ 
    $.$P = function() { 
     if (this instanceof $.$P) { 
      return this; 
     } else { 
      return new $.$P(); 
     } 
    }; 
    $.$P.prototype.then_ = function(fa, fb) { 
     /* A promise method that is the same as .then() 
     * but makes these extra methods available 
     * down-chain. 
     */ 
     return this.then(fa||null, fb||null).promise($.$P()); 
    } 
    $.$P.prototype.delay_ = function(ms) { 
     /* A promise method that 
     * introduces a down-chain delay. 
     */ 
     var promise = this; 
     function f(method) { 
      return function() { setTimeout(function(){ method.apply(null,this); }.bind(arguments), ms||0); }; 
     } 
     return $.Deferred(function(dfrd) { 
      promise.then(f(dfrd.resolve), f(dfrd.reject)); 
     }).promise($.$P()); 
    } 

    /* *********************************** 
    * Utility functions 
    * ***********************************/ 
    function consolidate(args) { 
     /* Convert mixed promises/arrays_of_promises to single array. 
     * Called by all the when_() methods below. 
     */ 
     return Array.prototype.slice.apply(args).reduce(function(arr, current) { 
      return arr.concat(current); 
     }, []); 
    } 

    /* *********************************** 
    * This section extends the jQuery namespace 
    * with a "jQuery.when_()" method. 
    * *********************************** 
    */ 
    $.extend({ 
     'when_': function() { 
      return $.when.apply(null, consolidate(arguments)).promise($.$P()).then_(function() { 
       return consolidate(arguments); 
      }); 
     }, 
    }); 
})(jQuery); 

Полная площадка также включает в себя целую кучу более статической и методу Обещания-экземпляр для других целей, и их развития является сутью пьесы.

основного правила использования Playgound заключаются в следующем:

  • Все детской площадке статику и обещающие методы заканчиваются в «_» подчеркивание.
  • Статические методы, например $.when_(), доступны только при установке Playgound.
  • Посылы в цепочке обещаний продлеваются путем включения статического метода, например .when_(), или цепочки .promise($.$P()).
  • В цепочке обещаний расширения остаются доступными (вниз по цепочке) с использованием методов «..._», а не стандартных методов, например .then_() вместо .then().

Так вот, как использовать его, чтобы навязать задержки, необходимые для вопроса:

jQuery(function($) { 
    var MYNAMESPACE = { 
     run: function (t) { 
      return $.when_() 
      .then_(function() { 
       log("call together"); 
       log("call together");  
      }) 
      .delay_(t) 
      .then_(function() { 
       log("call first"); 
      }) 
      .delay_(t) 
      .then_(function() { 
       log("call second"); 
      }); 
     } 
    } 
}); 

DEMO

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

на условии использования Экспозиция:

  • Как я говорю - это площадка.
  • В качестве адаптера для jQuery, а не патча, он ужасно неэффективен в местах. Хуже всего то, что некоторые методы создают промежуточное обещание в дополнение к тому, которое они возвращают.
  • Не проверен на стандарты, необходимые для использования в производственном коде, поэтому используйте с осторожностью.

И, наконец, рассмотрите вышеизложенное, если вы решите реализовать задержку с помощью jQuery. Намного гораздо проще использовать обещание lib, которое уже имеет метод .delay().

+0

Вы являетесь хозяином обещаний. Спасибо. – user348173

0

Редактировать, Обновлено

Попробуйте добавить свойство delay к jQuery.Deferred

delay: function(t) { 
     return this.then(function() { 
     var args = arguments; 
     return new $.Deferred(function(d) { 
      setTimeout(function() { 
      // return `data`, if any, to next method, e.g., `.then`, in chain 
      d.resolveWith(this, args) 
      }.bind(this), t || 0) 
     }).promise() 
     }) 
    } 

(function($) { 
 
    $.Deferred = function(a) { 
 
    var b = [ 
 
     ["resolve", "done", $.Callbacks("once memory"), "resolved"], 
 
     ["reject", "fail", $.Callbacks("once memory"), "rejected"], 
 
     ["notify", "progress", $.Callbacks("memory")] 
 
     ], 
 
     c = "pending", 
 
     d = { 
 
     delay: function(t) { 
 
      return this.then(function() { 
 
      var args = arguments; 
 
      return new $.Deferred(function(d) { 
 
       setTimeout(function() { 
 
       // return `data`, if any, to next method, e.g., `.then`, in chain 
 
       d.resolveWith(this, args) 
 
       }.bind(this), t || 0) 
 
      }).promise() 
 
      }) 
 
     }, 
 
     state: function() { 
 
      return c 
 
     }, 
 
     always: function() { 
 
      return e.done(arguments).fail(arguments), this 
 
     }, 
 
     then: function() { 
 
      var a = arguments; 
 
      return $.Deferred(function(c) { 
 
      $.each(b, function(b, f) { 
 
       var g = $.isFunction(a[b]) && a[b]; 
 
       e[f[1]](function() { 
 
       var a = g && g.apply(this, arguments); 
 
       a && $.isFunction(a.promise) 
 
       ? a.promise() 
 
        .done(c.resolve) 
 
        .fail(c.reject) 
 
        .progress(c.notify) 
 
       : c[f[0] + "With"](this === d 
 
        ? c.promise() 
 
        : this, g ? [a] : arguments) 
 
       }) 
 
      }), a = null 
 
      }).promise() 
 
     }, 
 
     promise: function(a) { 
 
      return null != a ? $.extend(a, d) : d 
 
     } 
 
     }, 
 
     e = {}; 
 
    return d.pipe = d.then, $.each(b, function(a, f) { 
 
     var g = f[2], 
 
     h = f[3]; 
 
     d[f[1]] = g.add, h && g.add(function() { 
 
     c = h 
 
     }, b[1^a][2].disable, b[2][2].lock), e[f[0]] = function() { 
 
     return e[f[0] + "With"](this === e ? d : this, arguments), this 
 
     }, e[f[0] + "With"] = g.fireWith 
 
    }), d.promise(e), a && a.call(e, e), e 
 
    } 
 

 
}(jQuery)); 
 

 
var p = { 
 
    run: function() { 
 
    return $() 
 
     .promise() 
 
     .then(function() { 
 
     console.log("call together"); 
 
     console.log("call together"); 
 
     // do stuff 
 
     // pass `data` to next `.then` 
 
     return "call first"; 
 
     }) 
 
     .delay(2000) 
 
     .then(function(data) { 
 
     console.log(data); 
 
     }) 
 
     .delay(2000) 
 
     .then(function() { 
 
     console.log("call second"); 
 
     }) 
 
    } 
 
}; 
 

 
p.run();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"> 
 
</script>

+0

«downvote» описание? – guest271314

+0

ОП дал очень конкретные требования к тому, что он хочет написать. Ваш ответ не соответствует этому. Имо это даже хуже, чем его рабочее решение с '.then (delay (2000))' – Bergi

+0

Я бы так подумал, да, хотя я бы не стал полностью заменять '$ .Deferred' другой реализацией, чтобы быть хорошим решением , И если вы намерены использовать 'resolWith', то вам, вероятно, следует передать исходные' this' и 'arguments' из обратного вызова' then', а не только первый параметр. – Bergi

0

Это мое решение. Я обертываю $.Deferred(afterBuild) и обертываю оригинал afterBuild, который в свою очередь обертывает метод .promise(obj), протягивая данный obj с обычным способом delay. Который использует window.setTimeout:

Примечание: оно только задерживает done ветвь.

function extendPromises(extensions) { 
 
    $.Deferred = (function (originalDeferred) { 
 
     return function (afterBuild) { 
 
      var newAfterBuild = function (d) { 
 
       d.promise = (function (originalPromise) { 
 
        return function (obj) { 
 
         return originalPromise.call(this, $.extend(obj, extensions)); 
 
        }; 
 
       })(d.promise); 
 
       if (afterBuild) afterBuild.apply(this, arguments); 
 
       return this; 
 
      }; 
 
      return originalDeferred.call(this, newAfterBuild); 
 
     }; 
 
    })($.Deferred); 
 
} 
 

 
extendPromises({ 
 
    delay: function (delay) { 
 
     return this.then(function (value) { 
 
      var d = $.Deferred(); 
 
      window.setTimeout(function() { 
 
       d.resolve(value); 
 
      }, delay); 
 
      return d.promise(); 
 
     }); 
 
    } 
 
}); 
 

 
// so now I can do: 
 
$.when("hello") 
 
.then(function (value) { $("#log").append(value+"\n"); return value; }) 
 
.delay(1000) 
 
.then(function (value) { $("#log").append(value); return value; });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<textarea id="log" rows=5></textarea>

Смежные вопросы