问题:
我一直在试图找出为什么我使用$ .when.apply()。then()来编写一些代码来解决多个promises,然后返回数据似乎触发不同步返回一个未解决的promise,然后在调用callback之后解析promise。
这是我一直在使用的模拟代码:
format(function(r) {
console.log('Done!', r);
});
function format(callback) {
var promises = [];
var items = [
{model: 'George'}
];
$.each(items, function (i, item) {
var selectedSeries = item.model;
promises.push(getSeriesDescription(selectedSeries));
});
$.when.apply($, promises).then(function (seriesInfo) {
console.log('Calling back');
callback(seriesInfo);
});
}
function getSeriesDescription(series) {
return new Promise(function (resolve, reject) {
getSeriesNotes().then(function (notes) {
console.log('Processing Notes...');
var rNotes;
$.each(notes.data, function () {
if (series !== 'undefined') {
console.log('Checking series ' + this.first_name + ' against ' + series + '...');
if (this.first_name == series) {
console.log('Series found!');
rNotes = this;
return false;
}
}
});
if (rNotes !== undefined) {
console.log('Returning series specific notes...');
resolve(rNotes);
} else {
resolve(notes);
}
});
});
}
function getSeriesNotes() {
return $.ajax({
url: 'https://reqres.in/api/users?delay=2',
dataType: 'json',
type: 'GET',
data: '',
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
我发现了什么:
经过大量的调试后,我终于意识到出乎意料的行为似乎是我正在使用的jQuery版本的结果。下面我有两个完全相同的代码的小提琴,不同版本的jQuery。 (我发布了jsfiddles,因为StackOverflow的版本没有jQuery的3.x版本)
jQuery 2.1.3:
https://jsfiddle.net/persononfire/1epgnfuh/2/
jQuery 3.1.1:
https://jsfiddle.net/persononfire/a9gc0y14/
通过观察控制台中的每一个,你会看到v3版本按照我的预期返回,而v2版本没有。
预期结果:
处理笔记......
(索引):58检查乔治对乔治的系列......
(指数):找到60系列!
(索引):67返回系列特定注释......
(index):46回电
(指数):31完成! {id:1,first_name:“George”,last_name:“Bluth”,avatar:“https://s3.amazonaws.com/uifaces/faces/twitter/calebogden/128.jpg”}
版本2.1.3首先返回最后两行,然后按照我期望的顺序返回其他所有行。
问题:
所以我的问题是;为什么两个版本的jQuery之间的结果有差异?我无法在看到我的版本文档中找到任何内容,因为它会导致两个版本的jQuery之间的行为差异。
我很欣赏对自己的启发有任何见解。
答案 0 :(得分:3)
jQuery v2&#39> s Deferred和Promise不符合Promises / A +规范(部分原因是它们先于当前版本),并且与本机Promise不可靠地互操作。 jQuery v3 fixed them因此它们可以与本机承诺互操作。 (虽然$.when
并非完全兼容。)
另外:如果您正在处理原生承诺,我建议尽可能远离$.when
。请改用Promise.all
。 :-)事实上,我的偏好要么完全保留在jQuery Deferred / promise生态系统内,要么完全保留在它之外(通过将任何jQuery Deferreds / Promises转换为实际的早期)。
这是$.when
没有使用原生承诺的一个相当简单的例子。
jQuery v2,无法正常工作:
function timeout(value, delay) {
console.log("creating promise for " + value);
return new Promise(resolve => {
setTimeout(() => {
console.log("resolving promise for " + value);
resolve(value);
}, delay);
});
}
$.when(
timeout(1, 100),
timeout(2, 200),
timeout(3, 300)
).then(result => {
console.log("then on $.when: ", result);
});
&#13;
.as-console-wrapper {
max-height: 100% !important;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;
jQuery v3,虽然注意到返回值只是第一个promise的值(因为$.when
对then
回调的调用是非标准的:它会传递每个将结果作为离散参数承诺):
function timeout(value, delay) {
console.log("creating promise for " + value);
return new Promise(resolve => {
setTimeout(() => {
console.log("resolving promise for " + value);
resolve(value);
}, delay);
});
}
$.when(
timeout(1, 100),
timeout(2, 200),
timeout(3, 300)
).then(result => {
console.log("then on $.when: ", result);
});
&#13;
.as-console-wrapper {
max-height: 100% !important;
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
&#13;
附注:new Promise
中getSeriesDescription
没有理由,getSeriesNotes().then
已经为您提供了可以使用的承诺。有趣的是,如果你修复它,它甚至可以在jQuery v2中运行:
format(function(r) {
console.log('Done!', r);
});
function format(callback) {
var promises = [];
var items = [{
model: 'George'
}];
$.each(items, function(i, item) {
var selectedSeries = item.model;
promises.push(getSeriesDescription(selectedSeries));
});
$.when.apply($, promises).then(function(seriesInfo) {
console.log('Calling back');
callback(seriesInfo);
});
}
function getSeriesDescription(series) {
return getSeriesNotes().then(function(notes) {
console.log('Processing Notes...');
var rNotes;
$.each(notes.data, function() {
if (series !== 'undefined') {
console.log('Checking series ' + this.first_name + ' against ' + series + '...');
if (this.first_name == series) {
console.log('Series found!');
rNotes = this;
return false;
}
}
});
if (rNotes !== undefined) {
console.log('Returning series specific notes...');
return rNotes;
} else {
return notes;
}
});
}
function getSeriesNotes() {
return $.ajax({
url: 'https://reqres.in/api/users?delay=2',
dataType: 'json',
type: 'GET',
data: '',
});
}
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
&#13;