2015-06-10 25 views
5

Tôi không thể tìm thấy chức năng delay hoặc wait cho lời hứa jQuery. Tôi đã tìm thấy một chức năng trên SO (Using jQuery.Deferred to avoid nested setTimeout callbacks):trì hoãn cho lời hứa jquery

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

Và, đó là cách làm thế nào tôi sử dụng nó:

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"); 
      }) 
    } 

tôi muốn mở rộng lời hứa hoặc đối tượng trì hoãn mà tôi có thể viết như sau:

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: Tôi cần chức năng chính xác cho những lời hứa. Chức năng này cho hiệu ứng. – user348173

+0

Có thể trùng lặp của [Có thể thêm các phương thức vào đối tượng lời hứa của JQuery không?] (Http://stackoverflow.com/q/30719454/1048572) (chỉ cần thêm phương thức '.delay' thay vì' .catch') – Bergi

+0

@ jfriend00: Vâng tất nhiên [có thể] (http://stackoverflow.com/a/30719727/1048572) ... nhưng không dễ dàng như mở rộng một nguyên mẫu. – Bergi

Trả lời

3

Như @Bergi nói jQuery Deferreds/Promises không thể mở rộng bằng cách thừa kế nguyên chủng.

Thay vào đó, các mô hình được chấp nhận bởi jQuery là để cho phép các trường hợp Promise cá nhân để được mở rộng với cú pháp:

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/ 

Bằng việc xác định một constructor với một loạt các phương pháp, bất kỳ jQuery hoãn hoặc Promise có thể được mở rộng với cú pháp đơn giản

.promise(Constructor()) 

trong chưa được công bố của tôi, cung cấp tài liệu jQuery hứa hẹn sân chơi, các nhà xây dựng được đặt tên $P và giữ trong không gian tên jQuery, vì thế mà cú pháp thực tế tôi sử dụng là:

.promise($.$P()) 

Bạn cần phải nhận thức được rằng, đối với hầu hết các phần, nó không phải là cần thiết để gọi $.$P() một cách rõ ràng là sân chơi bao gồm một phương pháp $.when_() mà trả về một Promise đã mở rộng.

Dưới đây là một phiên bản rút gọn của sân chơi với vừa đủ để cung cấp một phương pháp .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); 

đầy đủ Các sân chơi cũng bao gồm một bó toàn bộ tĩnh hơn và phương pháp hứa hẹn sơ thẩm đối với các mục đích khác, và phát triển chúng là bản chất của vở kịch.

Mặt đất-quy tắc sử dụng các Playgound như sau:

  • Tất cả các phương pháp tĩnh và hứa hẹn của sân chơi kết thúc bằng "_" dấu gạch dưới.
  • Phương pháp tĩnh, ví dụ: $.when_(), được cung cấp chỉ bằng cách cài đặt Playgound.
  • Lời hứa trong chuỗi lời hứa được mở rộng bằng cách bao gồm một phương pháp tĩnh, ví dụ: .when_() hoặc chuỗi .promise($.$P()).
  • Trong chuỗi lời hứa, các phần mở rộng vẫn có sẵn (xuống chuỗi) bằng cách sử dụng phương pháp "..._" thay vì phương pháp chuẩn, ví dụ: .then_() thay cho .then().

Vì vậy, dưới đây là cách sử dụng nó để áp đặt sự chậm trễ theo yêu cầu của câu hỏi:

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

Trong bản demo, handler click của nút cho chỉ thêm về cách Sân chơi có thể được sử dụng.

provisos về việc sử dụng các sân chơi:

  • Như tôi đã nói - đó là một sân chơi .
  • Là một bộ điều hợp cho jQuery, không phải là bản vá, nó vô cùng hiệu quả ở những nơi. Khía cạnh tồi tệ nhất là một số phương pháp tạo ra một lời hứa trung gian ngoài lời hứa mà họ quay trở lại.
  • Không được kiểm tra theo các tiêu chuẩn cần thiết để sử dụng trong mã sản xuất, vì vậy hãy thận trọng khi sử dụng.

Và cuối cùng, chỉ xem xét ở trên nếu bạn quyết tâm triển khai chậm trễ với jQuery. Nó đơn giản hơn nhiều khi sử dụng lib lời hứa đã có phương thức .delay().

+0

Bạn là bậc thầy về những lời hứa. Cảm ơn bạn. – user348173

0

chỉnh sửa, cập nhật

Hãy thử thêm tài sản delay-0.123.

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

mô tả "downvote"? – guest271314

+0

OP đã đưa ra những yêu cầu rất cụ thể về những gì anh ấy muốn viết. Câu trả lời của bạn không tuân thủ điều đó. Imo thậm chí còn tệ hơn giải pháp làm việc của anh ta với '.then (delay (2000))' – Bergi

+0

Tôi nghĩ vậy, mặc dù tôi sẽ không xem xét thay thế hoàn toàn '$ .Deferred' bằng cách triển khai khác để trở thành giải pháp tốt . Và nếu bạn có ý định sử dụng 'resolveWith', thì có lẽ bạn nên vượt qua' this' và 'arguments' ban đầu từ cuộc gọi lại' then', không chỉ tham số đầu tiên. – Bergi

0

Đây là giải pháp của tôi. Tôi quấn $.Deferred(afterBuild) và bọc gốc afterBuild mà lần lượt kết thúc theo phương pháp .promise(obj), mở rộng cho sẵn obj với phương thức tùy chỉnh delay. Trong đó sử dụng window.setTimeout:

Lưu ý: nó chỉ trì hoãn chi tiết done nhánh.

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>

Các vấn đề liên quan