【问题标题】:Handle the events of the beginning and end of an ajax request sent by a third-party library处理第三方库发送的ajax请求开始和结束的事件
【发布时间】:2015-04-06 05:28:37
【问题描述】:

我在我的项目中使用了一个第三方库来发送一些 ajax 请求。这是一个非常复杂的库,它将它们发送到具有随机 GUID 的 url,所以我无法预测 GUID 是什么,因此无法预测确切的 url 是什么。

我希望能够处理它发送的 ajax 请求的开始和结束,这样我就可以显示一个 ajax 微调器或其他东西 - 通知用户正在发生一些事情。特别是当页面第一次加载时。

我试过这个,即使它已经完成但它没有工作:

$(document).ajaxStop(function () {
  alert('done');
});

document.ready 也没有按我需要的方式工作,因为 ajax 请求的响应在它之后返回。

同样,我不会发送那些 ajax 请求,而是由库发送它们。 为简单起见,我们可以假设只有一个 ajax 请求,而不是很多。而且我无法更改库的源代码。

有什么办法吗?

更新:

没有使用 jquery。它通过

动态创建脚本
    var s = document.createElement('script');
    s.src = url;
    s.async = true;
    s.onreadystatechange = s.onload = function(){
     //.... some stuff

【问题讨论】:

  • 你用的是什么库?
  • @DGS,网上没有的图书馆。
  • @AlexanderSupertramp 如果它调用 ajax 然后检查这个 jquery 函数api.jquery.com/ajaxComplete
  • 我很确定全局 ajax 事件处理程序仅在使用 jQuery 进行事件时才有效。如果库不使用 jQuery,它可能不会注册事件
  • Global Ajax Event Handlers 可能适合您的需求。没有本地全局事件可以挂钩所有 XHR 请求。您可以尝试填充原型,但这可能不适用于某些浏览器,这取决于它们如何实现本机对象。我在看着你,IE。如果您确实尝试填充原型,则必须先在文档上执行该操作,然后再将有问题的库添加到页面中。

标签: javascript jquery ajax


【解决方案1】:

没有与 AJAX 请求相关的本地全局事件。这是部分,因为没有完整的跨浏览器实现标准。大多数浏览器使用XMLHttpRequest,IE使用ActiveXObject

如 cmets 中所述,jQuery 实现了Global Ajax Event Handlers,特别是ajaxStart()ajaxStop()。这些为您提供了一个挂钩所有 ajax 事件的地方,并且由于 jQuery 为这些事件提供了统一的 API,您不必担心浏览器之间的实现差异。

jQuery 事件仅有助于处理同样使用 jQuery 的请求。对于不使用库发起的请求,在包含库之前或之后,这些事件不会被 jQuery 触发,因为 jQuery 根本不知道请求发生了——没有全局事件给你,没有全局事件给 jQuery。

这给你留下了最后一个有点极端的选择——干涉原型。根据您需要做什么,这可以通过两种方式完成。要简单地停止所有请求,您可以将其他代码将依赖的对象替换为空。尝试发出 AJAX 请求的脚本只会失败。您可以稍后恢复对象。这是一个非跨浏览器的模型:

<head>
    <script>
        var oldXMLHttpRequest = XMLHttpRequest;
        XMLHttpRequest = false; // now all ajax requests fail
    </script>

    <!-- include the problematic library here -->

    <script>
        XMLHttpRequest = oldXMLHttpRequest; // now they work again!
        oldXMLHttpRequest = null;
    </script>

这是一个概念验证(未针对 IE 进行测试,但应该可以工作):http://jsfiddle.net/GRMule/wk0f7oeq/

如果目标不是停止请求,而是提前采取一些行动,您可以编写一个行为类似于 XMLHttpRequest/ActiveXObject 的对象,但允许您连接到请求。将 XMLHttpRequest(或 IE 对应项)替换为您的填充对象,然后在您的工作完成后可选择恢复原始对象。这有点涉及,但不是太难。与其让XMLHttpRequest 为假,不如让它成为您的功能替换对象。

不过,有些浏览器可能不喜欢您篡改原生对象,因此请务必在所有目标平台上测试这两种方法。

【讨论】:

    【解决方案2】:

    这看起来像一个 jsonp 回调。

    JSONP 的工作方式与您在帖子 update 中编写代码的方式相似。但更正式的理解见this

    假设您的库的编写方式不允许您在关键阶段(例如在 jsonp 请求之前)调用某些例程(函数),并且在 jsonp 请求完成后...您可以覆盖 appendChild 例程如here所述。

    您的重点是扩展appendChild 的功能。拦截script元素的插入;将处理程序附加到它。你已经完成了......我希望......

    当然,将其投入生产是个坏主意。

    http://plnkr.co/edit/ijElm8bQ5u895TMsYJ6D?p=preview

    var f = Element.prototype.appendChild;
    var precb = function() {
      console.log('precb called');
    };
    
    var postcb = function() {
      console.log('postcb called');
    };
    
    Element.prototype.appendChild = function() {
      var args = arguments;
      var el = args[0];
    
      if(el.tagName && el.tagName.toString().toLowerCase() === 'script') {
        precb();
        el.addEventListener('load', postcb, false);
      }
      f.apply(this, args);
    };
    

    【讨论】:

    • 1) 和jsonp有什么关系? 2) 为什么假设这个el.addEventListener('load', , postcb, false); 将在我们收到来自服务器的ajax 响应后立即执行? 3)它如何适用于我的案例 - 我应该在哪里插入所有这些?
    • jsonp - 这就是我可以从您的 SO 帖子中得出的代码模式...您是否浏览过我发布的示例 plunk...?
    猜你喜欢
    • 2012-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多