在 .each() 循环中未解决的承诺
Promises not resolved in a .each() loop
我必须 运行 一个递归过程,但 promise 没有按我的意愿工作。这是代码:
var openAllLeves = function () {
openAll = 1;
$.when(openLevels()).then(openAll = 0);
}
var openLevels = function () {
var promises = [];
$('.myClass:not([data-type="T"])').each(function () {
var defer = $.Deferred();
$.when(loadLine($(this)).then(promises.push(defer)));
});
return $.when.apply(undefined, promises).promise();
}
var loadLine = function (thisObj) {
var defer = $.Deferred();
switch(nivel) {
case 1:
$.when(getPT($(thisObj).attr('data-a'))).then(defer.resolve());
break;
case 2:
// ...
}
return defer.promise();
}
var getPT = function (psn) {
var defer = $.Deferred();
var payload = { /* parameters... */ };
$.ajax({
url: webmethod,
data: payload,
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
timeout: 10000,
success: function (data) {
$.when(paintPT(data)).then(function () {
if (openAll)
openLevels(), defer.resolve();
});
}
});
return defer.promise();
}
我的问题是 openAll 的值在 ajax 函数成功代码中被计算之前变为 0,因此只执行一次迭代并且没有完成递归。看起来 .then 是在解析承诺数组之前执行的。
代码有点混乱,如有任何帮助,我们将不胜感激。
提前致谢。
代码中的一个大问题是您在 then 回调上调用函数而不是将它们传递给它。例如:
.then(defer.resolve());
通过这种方式,您将 defer.resolve() 的值传递给 then 回调,而不是应该传递的函数在异步操作完成时调用。你应该这样做:
.then(defer.resolve.bind(defer));
其余代码也是如此。
你应该看看承诺 spec
特别是
If onFulfilled is not a function, it must be ignored.
编辑
正如 Bergi 所指出的,您应该避免延迟反模式。
避免 deferred antipattern!
还有,当你给.then()
传东西的时候,一定是回调函数,调用promises.push(defer)
、defer.resolve()
、openAll = 0
之类的是不行的,会立即执行该表达式,而不是等待承诺。
$.when()
和 .promise()
调用大多是多余的。放下它们。
function openAllLeves () {
openAll = 1;
openLevels().then(function() {
openAll = 0
});
}
function openLevels() {
var promises = [];
$('.myClass:not([data-type="T"])').each(function () { // using `map` would be even better
promises.push(loadLine($(this)));
});
return $.when.apply($, promises);
}
function loadLine(thisObj) {;
switch(nivel) {
case 1:
return getPT($(thisObj).attr('data-a'))
case 2:
// ...
}
}
function getPT(psn) {
var payload = { /* parameters... */ };
return $.ajax({
url: webmethod,
data: payload,
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
timeout: 10000,
}).then(function (data) {
return paintPT(data);
}).then(function () {
if (openAll)
openLevels();
});
}
顺便说一句,您可能希望将 if (openAll) openLevels();
链接到 openLevels()
的 return 值,而不是每个请求承诺。
谢谢你们的回复。我正在研究这个变化。这样,我了解到 .then() 仅在传递函数时等待承诺。所以在 .then() 中解决承诺的正确方法是..
.then(function() {
defer.resolve();
})
?
我必须 运行 一个递归过程,但 promise 没有按我的意愿工作。这是代码:
var openAllLeves = function () {
openAll = 1;
$.when(openLevels()).then(openAll = 0);
}
var openLevels = function () {
var promises = [];
$('.myClass:not([data-type="T"])').each(function () {
var defer = $.Deferred();
$.when(loadLine($(this)).then(promises.push(defer)));
});
return $.when.apply(undefined, promises).promise();
}
var loadLine = function (thisObj) {
var defer = $.Deferred();
switch(nivel) {
case 1:
$.when(getPT($(thisObj).attr('data-a'))).then(defer.resolve());
break;
case 2:
// ...
}
return defer.promise();
}
var getPT = function (psn) {
var defer = $.Deferred();
var payload = { /* parameters... */ };
$.ajax({
url: webmethod,
data: payload,
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
timeout: 10000,
success: function (data) {
$.when(paintPT(data)).then(function () {
if (openAll)
openLevels(), defer.resolve();
});
}
});
return defer.promise();
}
我的问题是 openAll 的值在 ajax 函数成功代码中被计算之前变为 0,因此只执行一次迭代并且没有完成递归。看起来 .then 是在解析承诺数组之前执行的。
代码有点混乱,如有任何帮助,我们将不胜感激。 提前致谢。
代码中的一个大问题是您在 then 回调上调用函数而不是将它们传递给它。例如:
.then(defer.resolve());
通过这种方式,您将 defer.resolve() 的值传递给 then 回调,而不是应该传递的函数在异步操作完成时调用。你应该这样做:
.then(defer.resolve.bind(defer));
其余代码也是如此。 你应该看看承诺 spec
特别是
If onFulfilled is not a function, it must be ignored.
编辑
正如 Bergi 所指出的,您应该避免延迟反模式。
避免 deferred antipattern!
还有,当你给.then()
传东西的时候,一定是回调函数,调用promises.push(defer)
、defer.resolve()
、openAll = 0
之类的是不行的,会立即执行该表达式,而不是等待承诺。
$.when()
和 .promise()
调用大多是多余的。放下它们。
function openAllLeves () {
openAll = 1;
openLevels().then(function() {
openAll = 0
});
}
function openLevels() {
var promises = [];
$('.myClass:not([data-type="T"])').each(function () { // using `map` would be even better
promises.push(loadLine($(this)));
});
return $.when.apply($, promises);
}
function loadLine(thisObj) {;
switch(nivel) {
case 1:
return getPT($(thisObj).attr('data-a'))
case 2:
// ...
}
}
function getPT(psn) {
var payload = { /* parameters... */ };
return $.ajax({
url: webmethod,
data: payload,
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
timeout: 10000,
}).then(function (data) {
return paintPT(data);
}).then(function () {
if (openAll)
openLevels();
});
}
顺便说一句,您可能希望将 if (openAll) openLevels();
链接到 openLevels()
的 return 值,而不是每个请求承诺。
谢谢你们的回复。我正在研究这个变化。这样,我了解到 .then() 仅在传递函数时等待承诺。所以在 .then() 中解决承诺的正确方法是..
.then(function() {
defer.resolve();
})
?