jQuery Deferrable,Deferred和一般推迟之间的混淆

时间:2014-06-18 13:21:34

标签: javascript jquery jquery-deferred

我下载了一个名为jsdeferred的库,试图帮助我解决一些代码流问题,但我有点迷失,因为它的示例和... 'documentation'是有些事情有点不清楚。但是当我不停地阅读和挖掘,当然还有在阳光下搜索一切时,我也发现jQuery有自己的Deferred()系统。我正在这里联系,以获得适当的背景。

Link to jsDeferred Library

Link to jQuery.Deferred()

问题

我需要找到一种方法来告诉页面“坚持到最后一件事情完成”

这是想法 jsdeffered 所做的。所以我的问题的一部分是在问我应该使用哪个? jsDeferred或jQuery.Deferred(); 然后如何使用,如下所述。

情况

我的情况就是这样,简而言之,我需要执行以下行为。

  • 页面加载,view model已定义

这是使用kendo ui mvvm来声明我的视图模型,因此它是kendo.data.ObservableObject

  • 对数据库进行$.ajax调用以获取一些默认模型数据

这是我遇到的最麻烦的地方。在完成$.ajax之前,我需要一切“坚持”。但是如果我能帮助的话,我不想把所有内容都包在$.ajax().done(r)中。这看起来/感觉非常草率,有时令人困惑。

  • 呈现页面上的其他小部件,它们通过kendo ui Remote DataSource完成各自的数据库查询。

这些实际上是按预期工作的。

  • jQuery Validate已连接到视图,默认设置已经设置。

这也是按预期工作的。

    调用
  • kendo.bind('body', viewModel);来执行模型绑定。

现在这是我遇到麻烦的地方,回到step 2我正在进行$.ajax通话。持续发生的事情是kendo.bind$.ajax完成之前被触发。我可以将它放在$.ajax({}).done();函数中,并且对于这个确切的一个特定页面确实有效,但是还有许多其他情况不合适。

我尝试了什么

首先,我会清楚jsdeferred文档对我来说非常不清楚,因为逐字运行其样本实际上并不起作用。我不断被告知next is not defined之类的。我最终发现,在您第一次致电Deferred.之前,您必须有一个隐含的next

所以这就是我想到会发生的事情......

var viewModel = new kendo.data.ObservableObject({
   // various view model properties defined
});

Deferred.define();

next(function() { // let's call this STEP 1
   $.ajax({
      // data for ajax to controller
   }).done(function(result) {
      // perform operations with result
   });
}).
next(function() { // let's call this STEP 2
   $('#dropdownlist_target').kendoDropDownList({
      // parameters, remote data source for drop down list, etc.
   }).data("kendoDropDownList");
}).
next(function() { // let's call this STEP 3
   $('form').validate({
      // any extra form validation stuff
   });
}). 
next(function(){ // let's call this STEP 4
   kendo.bind('body', viewModel);
});

我相信,当前一个完成时,这些将一个接一个地运行。但那是正在发生的事情。在STEP 1STEP 2, 3正在运行时,4仍处于抓取过程中。

这似乎与没有jsdeferred库的代码运行方式有任何不同。所以我很困惑,绝对会喜欢这里的一些帮助。我需要STEP 1才能在STEP 2点火之前完全完成。

2 个答案:

答案 0 :(得分:2)

问题在于next()希望您返回您想要等待的 thing 。在第一步中,您没有返回任何内容。因此jsdeferred假设您正在执行同步操作(已经完成),因此它继续执行步骤2.

相反,请返回jQuery.Deferred()来电中返回的$.ajax()。然后,jsdeferred将等待执行步骤2之前完成


无论如何,我都要转储jsdeferred。正如您所知,jQuery具有完全成熟的延迟实现。我不确定jsdeferred会给派对带来什么。

使用$.ajax().done(r)并非草率。异步行为是事件驱动语言的核心,JavaScript就是其中之一。拥抱它,或者你在生命的早期试图避免它

如果您还原为jQuery的延迟实现,您可能希望then()为您提供next()的语义;

$.ajax({
   // data for ajax to controller
}).done(function(result) {
   // perform operations with result
}).then(function () {
    $('#dropdownlist_target').kendoDropDownList({
       // parameters, remote data source for drop down list, etc.
    }).data("kendoDropDownList");

    $('form').validate({
       // any extra form validation stuff
    });

    kendo.bind('body', viewModel);
}).then(function () {
    // Note you can chain then()'s as well.
});

答案 1 :(得分:1)

您可以在then结果上使用$.ajax()方法,就像使用jsDeferred的next帮助器一样。一般来说,then是一种比done更灵活的方法。正如Matt在他的回答中指出的那样,在基于承诺的编程中忘记return处理程序中的新承诺是一个常见错误,导致它过早地使用undefined解决,而不是等待新的承诺。

$.ajax({  // let's call this STEP 1
   // data for ajax to controller
}).
then(function(result) {
   // perform operations with result
}).
then(function() { // let's call this STEP 2
   $('#dropdownlist_target').kendoDropDownList({
      // parameters, remote data source for drop down list, etc.
   }).data("kendoDropDownList");
}).
then(function() { // let's call this STEP 3
   $('form').validate({
      // any extra form validation stuff
   });
}). 
done(function(){ // let's call this STEP 4
   kendo.bind('body', viewModel);
});

请注意,在我的重构中,所有这些then将立即执行,除非返回新的promise。所以你也可以将它们结合起来。

then接受一个返回值或promise的函数,并返回一个新的promise。如果其函数返回一个值,则会立即使用该值解析新的promise。如果它的函数返回了一个promise,那么该promise将作为新的promise传递。请注意,jQuery的then仅适用于jQuery版本> = 1.8。