当美元.应用于延迟数组,在所有解析之前运行
$.when.apply on array of deferreds runs before all resolved
尝试为某些类构建先决条件链。由于未知的递归深度,每次创建新课程时都会运行一个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 pending, 8 resolved.
完成后有92个ajax调用。所有92个返回良好的数据(没有错误/失败)。
我怎么能告诉它运行.then()
后所有dfd在数组(不只是一个在数组时$.when.apply
定义?)
大致思路如下。我在这里有几个目标。
- 去掉你正在累积承诺的全局变量
- 让所有嵌套的承诺都链接到它们的父承诺上,这样你就可以等待父承诺,一切都会正常工作。
- 链接承诺,我用
.then()
处理程序替换$.getJSON()
中的完成回调,然后从.then()
处理程序返回嵌入的承诺。这会自动将它们链接到父元素上,所以父元素本身不会被解析,直到嵌入的元素也被解析。而且,这对任意深度的嵌入式承诺都有效。 - 去掉在承诺已经存在时创建和解决新的差异的反模式。
在摆脱全局变量的过程中,我不得不从course
构造函数中删除承诺的创建,因为它不能返回承诺。因此,我创建了一个course.init()
,其中创建并返回了承诺。然后,我们可以在局部变量中累积承诺,而避免全局变量。
总的思路是:
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();
})
});
});
这个成功了。我感谢大家的评论。它帮助我意识到这个问题是$.when.apply
在$.when.apply
被定义时只观察DFDS
中的延迟。
我把这个函数放在课程构造函数.parse()
的$.getJSON
回调中。
function checkDFDS() {
var completed = 0;
$.each(DFDS,function() {
if (this.state()=='resolved') completed++;
});
if (completed == DFDS.length) {
$.each(COURSES,function() {
this.render();
})
}
}
相关文章:
- 将函数的上下文应用于javascript变量
- 将CSS应用于printWindow.print();在Javascript中
- 如何将CSS(特别是填充/边距)应用于select下拉菜单的选项或optgroup
- $scope.apply()何时应用于angular
- Javascript非常简单:'阅读更多''显示较少'应用于Wordpress的功能
- 尝试应用于<tr>在ng单击中
- 如何将javascript仅应用于1个表单中的2个表单提交按钮中的1个
- 将脚本应用于Angular 2上的输入
- Json和$scope的角度之间的差异$eval应用于JSON字符串时
- 如何将参数应用于String.prototype.format函数
- 动态地将过滤器应用于 JSON.parse()
- $location更改不适用于ngchange,而是应用于ngclick
- 如何将 :empty 选择器应用于 XML 文档
- 如何仅在文本字段中有值时才将自定义过滤器应用于 ng-repeat
- 如何使用 JavaScript 将样式应用于 CKEditor 中的选定文本
- MongoDB 无法将$addToSet应用于 Meteor JS 中的非数组
- 将类应用于jquery ui对话框
- 将CSS应用于在JavaScript中创建的表-表的位置不正确
- 如果检查了输入,则将类应用于<身体>,没有jQuery
- 是否“;运行到完成”;应用于iframe内的代码