0

我正在扩展 jQuery 的ajaxPrefilter界面以向 AJAX 调用添加额外的功能;setRequestHeader()即在方法中使用将标头数据附加到 XHR 请求上beforeSend()。问题是,theajaxPrefilter和 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);​

现在,optionsoriginalOptions都可以包含beforeSend()方法,我希望options.beforeSend始终首先执行。这似乎是延迟/承诺使用的主要候选者,但由于beforeSend自动调用的事实,我不能这样做:

options.beforeSend = function(jqXHR) {
    // setting the request header; creating, resolving, and returning the Deferred
}

$.when(options.beforeSend(jqXHR)).then(function() {
    originalOptions.beforeSend();
});

正如预期的那样,这会导致options.beforeSend两次触发;由于它的定义语句和$.when调用。

Deferreds/promises 如何用于管理自动调用的方法,例如beforeSend

4

2 回答 2

1

关于控制beforeSend回调后发生的事情,只有两种选择:

  • 返回 false 以外的任何内容以允许请求继续进行,或者
  • 返回false以取消请求。

您确实可以在回调中发出 ajax 请求,但无论返回什么都会导致原始(外部)ajax 请求立即发出或取消。由于回调将无条件完成并返回,因此不可能通过延迟或其他方式使外部 ajax 依赖于内部。

对于您想要的效果,您可以在回调中,级联发出两个 ajax 请求(第二个依赖于第一个)并返回false以取消原始请求。

有一天,您可能想采用这种模式可能有一些模糊的原因,但是,如果原始请求被无条件地丢弃(通过返回 false),那只不过是实现两个 ajax 请求级联的复杂方式,而不是涉及beforeSend,即:

$.ajax({
    //options
}).done(function() {
    $.ajax({
        //options
    }).done(function(){
        //do stuff here
    });
});

.pipe()等价物。

总之,让 jQuery ajax 请求依赖于在其回调中编码的另一个异步操作似乎是不可能的beforeSend,但是可以通过不涉及beforeSend.

于 2012-12-19T04:14:56.290 回答
0

以下有点难看,但可以全局处理重新启动原始请求,而不是嵌套每个请求。例如,如果您需要令牌并且令牌已过期,则此示例依赖于由全局 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
        }
  }

});
于 2015-10-27T18:04:11.757 回答