如何在自动调用的函数(如.ajax()')上正确使用jQuery Deferred/promise;s beforeSend()?
我正在扩展jQuery的如何在自动调用的函数(如.ajax()')上正确使用jQuery Deferred/promise;s beforeSend()?,ajax,jquery,jquery-deferred,Ajax,Jquery,Jquery Deferred,我正在扩展jQuery的ajaxPrefilter接口,为AJAX调用添加额外的功能;即使用beforeSend()方法中的setRequestHeader()将标头数据固定到XHR请求上。问题是,ajaxPrefilter和ajax调用本身都可以包含beforeSend选项,其中一个或两个都可以包含异步功能 假设我的ajaxPrefilter看起来是这样的: (function($) { $.ajaxPrefilter(function(options, originalOptions
ajaxPrefilter
接口,为AJAX调用添加额外的功能;即使用beforeSend()
方法中的setRequestHeader()
将标头数据固定到XHR请求上。问题是,ajaxPrefilter
和ajax调用本身都可以包含beforeSend
选项,其中一个或两个都可以包含异步功能
假设我的ajaxPrefilter
看起来是这样的:
(function($) {
$.ajaxPrefilter(function(options, originalOptions, jqXHR) {
var auth = $.cookie("fake_site"),
normalizedRequest = $.Deferred();
if (originalOptions.authorizeUser) {
options.beforeSend = function() {
jqXHR.setRequestHeader("Authorization", "Session " + auth);
}
// resolving the jqXHR Deferred, statusCode handling, etc.
}
});
})(jQuery);
现在,选项和原始选项都可以包含beforeSend()
方法,我希望选项。beforeSend始终首先执行。这似乎是延迟/承诺用法的主要候选项,但由于自动调用了beforeSend
,因此我不能这样做:
options.beforeSend = function(jqXHR) {
// setting the request header; creating, resolving, and returning the Deferred
}
$.when(options.beforeSend(jqXHR)).then(function() {
originalOptions.beforeSend();
});
正如预期的那样,这会导致选项。beforeSend
触发两次;由于其定义语句和调用时的$
如何使用延迟/承诺来管理自动调用的方法,例如beforeSend
?关于控制beforeSend
回调后发生的情况,只有两个选项:
- 返回除false以外的任何内容以允许请求继续,或
- 返回
false
以取消请求
您确实可以在回调中发出ajax请求,但是返回的任何内容都会导致立即发出或取消原始(外部)ajax请求。由于回调将完成并无条件返回,因此不可能通过延迟或其他方式使外部ajax依赖于内部ajax
为了达到您想要的效果,您可以在回调中级联发出两个ajax请求(第二个请求依赖于第一个请求),并返回false
以取消原始请求
有一天,可能会有一些模糊的原因让您想采用这种模式,但是,如果原始请求被无条件地丢弃(返回false),那么它只不过是一种以级联方式实现两个ajax请求的复杂方式,而不涉及在发送之前的
,即:
$.ajax({
//options
}).done(function() {
$.ajax({
//options
}).done(function(){
//do stuff here
});
});
或类似的.pipe()
总之,使jQuery ajax请求依赖于在其beforeSend
回调中编码的另一个异步操作似乎是不可能的,但是可以通过不涉及beforeSend
的标准方法来实现所需的效果。下面的方法有点难看,但可以全局处理重新启动原始请求,而不是嵌套每个请求。例如,如果您需要一个令牌,但该令牌已过期,则此示例依赖于全局api.getToken()函数返回的承诺
$.ajaxSetup({
beforeSend: function(xhr,settings) {
var newTokenNeeded = false;
var originalSettings=settings;
var promise = api.getToken().then(function(data){
if(newTokenNeeded && typeof originalSettings.nested ==='undefined'){
originalSettings.nested=true;//this flag is used to prevent infinite loops
$.ajax(originalSettings);//here we re request the original, that we cancelled previously
}else{
xhr.setRequestHeader('Authorization', 'Bearer ' +data.t );
}
});
if(promise.state()==='pending'){
newTokenNeeded=true;
return false; //returning false cancels the original request
}
}
});