延迟数组上的$ .when.apply在全部解析之前运行

时间:2015-08-10 21:16:23

标签: javascript jquery ajax

尝试为某些类构建先决条件链。由于未知的递归深度,我有一个ajax调用,每次创建一个新课程时都会运行。 DFDS是一个存储延迟的全局数组。COURSES是一个全局的课程数组。

var DFDS = []; //define global DFDS
var course = function( options ) {
  ...
  var self = this;
  this.p = { //prereqs object
    a: [], // array for prereqs
    rgx: /([A-Z]\w+[\ ])\w+/g, 
    parse: function() {
      if (self.prereqs == '') return true;
      self.prereqs.replace(this.rgx,function(m) {
        //search through prereq string (self.prereqs) and run ajax for each match
        var id = m.split(' ');
        var dfd2 = $.Deferred();
        DFDS.push(dfd2);
        $.getJSON('/ajax/ajaxPrereqs.php',{subj:id[0],crs:id[1]},function(d) {
          var d = d[0];
          self.p.a.push(new course({
            ... //create new course in self.p.a[]
          }));
          dfd2.resolve();
        });
      });
    }
  };
  ...
  //run parse function when created
  this.p.parse();
  return this;
}

我能够获得所期望的结构,并将所有正确的课程加载到所有正确的self.p.a[]数组中。

所以要初始化顶级课程:

$.getJSON('/ajax/ajaxPrereqs.php',{subj:$('#subj').val()}, function(data) {

  $.each(data,function() {
    var d = this;
    COURSES.push(new course({
      s: d.subj,
      c: d.crs,
      t: d.titleshrt,
      crd: d.credits,
      chr: d.contacthrs,
      prereqs: d.prereqs
    }));
  });


  console.log(DFDS.length); //displays 10
  $.when.apply($, DFDS).then(function() {
    console.log('DFDS all done???');
    console.log(DFDS.length);
    $.each(DFDS,function() {console.log(this.state())})
    $.each(COURSES,function() {
      this.render();
    })
  });

});

问题:$.when.apply在所有延迟解决之前运行。我的控制台说:

24
(10) resolved
(14) pending

我还尝试每5毫秒运行一次这个日志记录功能:

var interval = setInterval(function() {
  console.log('--- intv ---');
  var pending = 0;
  var resolved = 0;
  $.each(DFDS,function() {
    switch(this.state()) {
      case 'pending': pending++; break;
      case 'resolved': resolved++; break;
      default: console.log('NOT PENDING OR RESOLVED');
    }
  });
  console.log(pending+' pending');
  console.log(resolved+' resolved');
},5);

$.when.apply运行之前的最后一个控制台条目是14个待处理,8个已解决。

完成后有92个ajax调用。所有92个返回良好数据(没有错误/失败)。

如何判断它在数组中的所有DFD之后运行.then()(当$.when.apply定义时,不仅仅是数组中的那些?)

2 个答案:

答案 0 :(得分:1)

这是一个大致的想法。我在这里有几个目标。

  1. 摆脱正在积累承诺的全局变量。
  2. 将所有嵌套的承诺链接到其父承诺上,这样您就可以等待父承诺,一切都会正常工作。
  3. 为了链接promises,我用$.getJSON()处理程序替换.then()中的完成回调,然后从.then()处理程序返回嵌入的promise。这会自动将它们链接到父节点上,这样父节点就不会被解析,直到嵌入节点也被解析。并且,这适用于任意深度的嵌入式承诺。
  4. 当已经存在可以使用的承诺时,摆脱创建和解决新的deffereds的反模式。
  5. 在摆脱全局变量的过程中,我不得不从course构造函数中删除promises的创建,因为它无法返回promise。所以,我创建了一个course.init(),其中创建并返回了promise。然后,我们可以在局部变量中累积promises并避免全局。

    所以,这是一般的想法:

    var course = function( options ) {
      ...
      var self = this;
    
      this.p = { //prereqs object
        a: [], // array for prereqs
        rgx: /([A-Z]\w+[\ ])\w+/g, 
        parse: function() {
          var promises = [];
          // check if we have any prereqs to process
          if (self.prereqs !== '') {
              self.prereqs.replace(this.rgx,function(m) {
                //search through prereq string (self.prereqs) and run ajax for each match
                var id = m.split(' ');
                promises.push($.getJSON('/ajax/ajaxPrereqs.php',{subj:id[0],crs:id[1]}).then(function(d) {
                  var d = d[0];
                  var c = new course({
                    ... //create new course in self.p.a[]
                  }));
                  self.p.a.push(c);
                  // chain all the new promises created by c.init() onto our master promise
                  // by returning a new promise from the .then() handler
                  return(c.init());
                }));        
              });
          }
          // return a master promise that is resolve when all the sub promises 
          // created here are all done
          return $.when.apply($, promises);
        }
      };
    
      // call this to run the initial parse
      // returns a single promise that is resolve when all the promises are done
      this.init = function() {
          return this.p.parse();
      };
    
      ...
      return this;
    }
    
    $.getJSON('/ajax/ajaxPrereqs.php',{subj:$('#subj').val()}, function(data) {
    
      var promises = [];
      var COURSES = [];
      $.each(data,function() {
        var d = this;
        var c = new course({
          s: d.subj,
          c: d.crs,
          t: d.titleshrt,
          crd: d.credits,
          chr: d.contacthrs,
          prereqs: d.prereqs
        });
        COURSES.push(c);
        promises.push(c.init());    
      });
      $.when.apply($, promises).then(function() {
        console.log('promises all done');
        console.log(promises.length);
        $.each(promises,function() {console.log(this.state())})
        $.each(COURSES,function() {
          this.render();
        })
      });
    });
    

答案 1 :(得分:0)

这很有用。我感谢大家的评论。它帮助我意识到$.when.apply在定义DFDS$.when.apply只监视$.getJSON中的延迟问题。

我将此函数放在课程构造函数.parse()的{​​{1}}回调中。

function checkDFDS() {
  var completed = 0;
  $.each(DFDS,function() {
    if (this.state()=='resolved') completed++;
  });
  if (completed == DFDS.length) {
    $.each(COURSES,function() {
      this.render();
    })
  }
}