试图在firefox中跟踪未完成的AJAX请求的数量

时间:2010-12-10 15:12:17

标签: javascript firefox xmlhttprequest greasemonkey sandbox

我使用Selenium测试Web应用程序,不允许修改应用程序的javascript代码。我试图通过使用GreaseMonkey来覆盖XMLHttpRequest.send来跟踪未完成的AJAX请求的数量。新的send()将基本上包装设置为onreadystatechange回调的内容,检查readyState,根据需要递增或递减计数器,并调用原始回调函数。

我遇到的问题似乎是一个特权问题,因为如果我只是浏览普通firefox浏览器中的页面,打开firebug并粘贴以下代码,它似乎工作正常:

document.ajax_outstanding = 0;
if (typeof XMLHttpRequest.prototype.oldsend != 'function') {
    XMLHttpRequest.prototype.oldsend = XMLHttpRequest.prototype.send;
    XMLHttpRequest.prototype.send = function() {
        console.log('in new send');
        console.log('this.onreadystatechange = ' + this.onreadystatechange);
        this.oldonreadystatechange = this.onreadystatechange;
        this.onreadystatechange = function() {
            if (this.readyState == 2) {
                /* LOADED */
                document.ajax_outstanding++;
                console.log('set ajax_outstanding to ' + document.ajax_outstanding);
            }
            this.oldonreadystatechange.handleEvent.apply(this, arguments);
            if (this.readyState == 4) {
                /* COMPLETED */
                document.ajax_outstanding--;
                console.log('set ajax_outstanding to ' + document.ajax_outstanding);
            }
        };
        this.oldsend.apply(this, arguments);
    };
}

现在,如果我在GreaseMonkey用户脚本中使用该片段的略微修改版本,如下所示:

unsafeWindow.document.ajax_outstanding = 0;
if (typeof unsafeWindow.XMLHttpRequest.prototype.oldsend != 'function') {
    unsafeWindow.XMLHttpRequest.prototype.oldsend = unsafeWindow.XMLHttpRequest.prototype.send;
    unsafeWindow.XMLHttpRequest.prototype.send = function() {
        GM_log('in new send');
        GM_log('this.onreadystatechange = ' + this.onreadystatechange);
        this.oldonreadystatechange = this.onreadystatechange;
        this.onreadystatechange = function() {
            if (this.readyState == 2) {
                /* LOADED */
                unsafeWindow.document.ajax_outstanding++;
                GM_log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding);
            }
            this.oldonreadystatechange.handleEvent.apply(this, arguments);
            if (this.readyState == 4) {
                /* COMPLETED */
                unsafeWindow.document.ajax_outstanding--;
                GM_log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding);
            }
        };
        this.oldsend.apply(this, arguments);
    };
}

我去了一个页面,做了一些导致AJAX请求的事情,我在javascript错误控制台中收到以下消息:

http://www.blah.com/gmscripts/overrides: in new send
uncaught exception: [Exception... "Illegal value" nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)" location: "JS frame :: file:///tmp/customProfileDir41e7266f56734c97a2ca02b1f7f528e1/extensions/%7Be4a8a97b-f2ed-450b-b12d-ee082ba24781%7D/components/greasemonkey.js :: anonymous :: line 372" data: no]

因此在尝试访问this.onreadystatechange

时似乎抛出了异常

据推测,这是由于沙盒环境造成的。 任何帮助将不胜感激。我不依赖于这个解决方案,因此欢迎任何其他建议我做我需要的。只是我尝试了其他几个,这似乎是最有希望的。要求是我需要确保计数器在之后达到0 ,readyState变为4并且onreadystatechange回调已经完成执行。

2 个答案:

答案 0 :(得分:3)

我自己做了一些事:http://jsfiddle.net/rudiedirkx/skp28agx/(2015年1月22日更新)

脚本(应先运行):

(function(xhr) {
    xhr.active = 0;
    var pt = xhr.prototype;
    var _send = pt.send;
    pt.send = function() {
        xhr.active++;
        this.addEventListener('readystatechange', function(e) {
            if ( this.readyState == 4 ) {
                setTimeout(function() {
                    xhr.active--;
                }, 1);
            }
        });
        _send.apply(this, arguments);
    }
})(XMLHttpRequest);

jsFiddle的测试脚本:

window.onload = function() {
    var btn = document.querySelector('button'),
        active = btn.querySelector('span');

    btn.onclick = function() {
        // jQuery for easy ajax. `delay` is a jsFiddle argument
        // to keep some requests active longer.
        jQuery.post('/echo/json/', {
            delay: Math.random() * 3,
        });
    };

    updateActive();

    function updateActive() {
        active.textContent = XMLHttpRequest.active;
        requestAnimationFrame(updateActive);
    }
};

它会在每个动画帧(每秒约60次)中更新按钮中的计数器,与AJAX请求分开。无论你做什么,无论多快,多点击它,计数器应该总是在几秒后结束。

答案 1 :(得分:1)

我最终使用了以下内容:

unsafeWindow.document.ajax_outstanding = 0;
if (typeof unsafeWindow.XMLHttpRequest.prototype.oldsend != 'function') {
    unsafeWindow.XMLHttpRequest.prototype.oldsend = unsafeWindow.XMLHttpRequest.prototype.send;
    unsafeWindow.XMLHttpRequest.prototype.send = function() {
        unsafeWindow.XMLHttpRequest.prototype.oldsend.apply(this, arguments);
        this.addEventListener('readystatechange', function() {
            if (this.readyState == 2) {
                /* LOADED */
                unsafeWindow.document.ajax_outstanding++;
                console.log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding);
            } else if (this.readyState == 4) {
                /* COMPLETED */
                unsafeWindow.document.ajax_outstanding--;
                console.log('set ajax_outstanding to ' + unsafeWindow.document.ajax_outstanding);
            }
        }, false);
    };
}