jQuery - .always() 回调过早触发
jQuery - .always() callback firing too soon
我正在开发一个客户端JS应用程序,该应用程序应该读取CSV文件,每行进行几次API调用,然后将结果写回CSV。我坚持的部分是如何编排请求并在所有请求完成后启动函数。这是我到目前为止所拥有的:
var requests = [];
// loop through rows
addresses.forEach(function (address, i) {
// make request
var addressRequest = $.ajax({
dataType: 'json',
url: 'http://api.com/addresses/' + address,
success: function (data, textStatus, jqXhr) { APP.didGetAddressJson(data, i, jqXhr) },
error: function (jqXhr, textStatus, errorThrown) { APP.didFailToGetAddressJson(errorThrown, i) },
});
requests.push(addressRequest);
// make some more requests (handled by other success functions)
});
// leggo
$.when.apply($, requests).done(APP.didFinishGeocoding);
问题是,如果其中一行抛出 404,则不会调用 done
函数。我将其切换到 always
现在它被调用,但不是在最后 - 如果我将每个回调的执行记录到控制台,它通常在中间的某个地方。但是,如果我编辑 CSV 以便没有错误,它会按预期在最后调用。我在这里做什么让always
提前开火的事情吗?
更新:可能只是控制台无序地登录吗?
您需要防止错误发送错误,通过$.when.apply($, requests)
错误路径返回的承诺。
这可以通过以下方式实现:
- 将
.then()
链接到$.ajax()
调用,而不是将"成功"和"错误"处理程序指定为$.ajax()
选项。 - 通过转换为成功来处理错误(因为这是jQuery,你必须从错误处理程序返回一个已解决的承诺)。
此方法还允许您控制最终交付给APP.didFinishGeocoding()
通过一些假设,代码的一般形状应如下所示:
function foo () {//assume there's an outer function wrapper
var errorMarker = '**error**';
var requests = addresses.map(function (address, i) {
return $.ajax({
dataType: 'json',
url: 'http://api.com/addresses/' + address
}).then(function (data, textStatus, jqXhr) { //success handler
return APP.didGetAddressJson(data, i, jqXhr); //whatever APP.didGetAddressJson() returns will appear as a result at the next stage.
}, function (jqXhr, textStatus, errorThrown) { // error handler
APP.didFailToGetAddressJson(errorThrown, i);
return $.when(errorMarker);//errorMarker will appear as a result at the next stage - but can be filtered out.
});
// make some more requests (handled by other success functions)
});
return $.when.apply($, requests).then(function() {
//first, convert arguments to an array and filter out the errors
var results = Array.prototype.slice.call(arguments).filter(function(r) {
return r !== errorMarker;
});
//then call APP.didFinishGeocoding() with the filtered results as individual arguments.
return APP.didFinishGeocoding.apply(APP, results);
//alternatively, call APP.didFinishGeocoding() with the filtered results as an array.
//return APP.didFinishGeocoding(results);
});
}
根据需要进行调整。
尝试通过whenAll
函数传递已解决的、被拒绝的 jQuery 承诺对象,在whenAll
完成时过滤已解决、拒绝的 .then()
内的承诺对象。参见 Jquery Ajax 防止延迟顺序循环中的失败
(function ($) {
$.when.all = whenAll;
function whenAll(arr) {
"use strict";
var deferred = new $.Deferred(),
args = !! arr
? $.isArray(arr)
? arr
: Array.prototype.slice.call(arguments)
.map(function (p) {
return p.hasOwnProperty("promise")
? p
: new $.Deferred()
.resolve(p, null, deferred.promise())
})
: [deferred.resolve(deferred.promise())],
promises = {
"success": [],
"error": []
}, doneCallback = function (res) {
promises[this.state() === "resolved"
|| res.textStatus === "success"
? "success"
: "error"].push(res);
return (promises.success.length
+ promises.error.length) === args.length
? deferred.resolve(promises)
: res
}, failCallback = function (res) {
// do `error` notification , processing stuff
// console.log(res.textStatus);
promises[this.state() === "rejected"
|| res.textStatus === "error"
? "error"
: "success"].push(res);
return (promises.success.length
+ promises.error.length) === args.length
? deferred.resolve(promises)
: res
};
$.map(args, function (promise, index) {
return $.when(promise).always(function (data, textStatus, jqxhr) {
return (textStatus === "success")
? doneCallback.call(jqxhr, {
data: data,
textStatus: textStatus
? textStatus
: jqxhr.state() === "resolved"
? "success"
: "error",
jqxhr: jqxhr
})
: failCallback.call(data, {
data: data,
textStatus: textStatus,
jqxhr: jqxhr
})
})
});
return deferred.promise()
};
}(jQuery));
例如
var request = function (url) {
return $.ajax({
url: "http://api.com/addresses/" + url,
dataType: "json"
})
}
, addresses = [
["/echo/json/"], // `success`
["/echo/jsons/"], // `error`
["/echo/json/"], // `success`
["/echo/jsons/"], // `error`
["/echo/json/"] // `success`
];
$.when.all(
$.map(addresses, function (address) {
return request(address)
})
)
.then(function (data) {
console.log(data);
// filter , process responses
$.each(data, function(key, value) {
if (key === "success") {
value.forEach(function(success, i) {
console.log(success, i);
APP.didGetAddressJson(success.data, i, success.jqxhr);
})
} else {
value.forEach(function(error, i) {
console.log(error, i);
APP.didFailToGetAddressJson(error.jqxhr, i)
})
}
})
}, function (e) {
console.log("error", e)
});
JSFIDDLE http://jsfiddle.net/guest271314/ev4urod1/
相关文章:
- AngularJS:我可以跳过函数参数回调吗
- 要求未定义JS回调参数
- MeteorJS:在带有回调的vzaar api上正确使用wrapAsync
- 自引用回调
- 测试Angular Service解决错误回调中的promise
- 如何将一个JavaScript函数回调为多个函数
- JavaScript回调函数
- 用于回调的javascript参数
- 将json回调数据转换为日期
- 承诺在非节点式回调上使用Bluebird
- 如何在回调函数中执行流
- 回调函数中传递参数的困难(Google Map API Markers)
- Soundcloud Javascript SDK 3.0-回调无法读取属性'connectCallback
- 如何使用jqueryAJAX从页面中回调多个变量
- jquery Onclick函数带有导致双击的回调排序函数
- Javascript点击事件回调不起作用
- 是否保证传递给 always 函数的回调将在函数(数据)回调完成其工作后调用
- 角度等价于 jQuery deferred.always() 回调
- Qunit jquery ajax测试,for always和done回调
- jQuery - .always() 回调过早触发