2010-12-10 52 views
6

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

说我有似乎是一个特权问题,因为如果我只是浏览一个网页在一个正常的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回调完成执行。

回答

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); 
    }; 
} 
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请求分开。无论你做什么,无论多么快速,你点击它,计数器应该在几秒钟后总是以0结束。

+4

你真的给了本地主机地址还是我的眼睛? =)) – 2010-12-10 18:24:12

+0

请注意,对XMLHttpRequest.send的这种修改需要在发送任何AJAX请求之前安装,否则计数器可能会出错。另外,我认为在调用'this._onreadystatechange'之后递减'active'可能会更好(如果您认为某个请求在其事件处理程序结束之前处于活动状态)。 – seanf 2015-01-22 07:57:19