我在某些IE7计算机上遇到了堆栈溢出错误。
此功能可下载一堆基于URL的资源,并且不会对它们执行任何操作。它在我的登录页面上运行,其目的是在您输入凭据时获取静态内容,这样当您真正需要它时,浏览器就可以从其本地缓存中获取它。
// Takes an array of resources URLs and preloads them sequentially,
// but asynchronously, using an XHR object.
function preloadResources(resources) {
// Kick it all off.
if (resources.length > 0) {
var xhr = getXHRObject(); // Prepare the XHR object which will be reused for each request.
xhr.open('GET', resources.shift(), true);
xhr.onreadystatechange = handleReadyStateChange;
xhr.send(null);
}
// Handler for the XHR's onreadystatechange event. Loads the next resource, if any.
function handleReadyStateChange() {
if (xhr.readyState == 4) {
if (resources.length > 0) {
xhr.open('GET', resources.shift(), true);
xhr.onreadystatechange = arguments.callee;
xhr.send(null);
}
}
}
// A safe cross-browser way to get an XHR object.
function getXHRObject() {
// Clipped for clarity.
}
} // End preloadResources().
它被称为:
preloadResources([
'http://example.com/big-image.png',
'http://example.com/big-stylesheet.css',
'http://example.com/big-script.js']);
它以递归方式处理一系列URL。我认为它不容易受到堆栈溢出错误的影响,因为每个递归都是从异步事件调用的 - XHR的onreadystatechange
事件(注意我异步调用xhr.open()
)。我觉得这样做可以防止它堆积。
我不知道堆栈是如何失控的? 我哪里出错?
答案 0 :(得分:2)
使用计时器执行递归可防止出现堆栈溢出问题。
// Handler for the XHR's onreadystatechange event. Loads the next resource, if any.
function handleReadyStateChange() {
if (xhr.readyState == 4 && resources.length > 0) {
setTimeout(function() {
xhr.open('GET', resources.shift(), true);
xhr.onreadystatechange = handleReadyStateChange;
xhr.send(null);
}, 10);
}
}
我猜彼此链接XHR请求会占用堆栈。将它们与计时器链接在一起可以防止这种情况 - 至少在IE7中。我没有在其他浏览器上看到这个问题,所以我不知道。
答案 1 :(得分:0)
您是否可以控制日志或提醒arguments.callee
的值?我很好奇如果它从arguments
函数解析为preloadResources()
变量而不是handleReadyStateChange()
会发生什么。对我来说似乎不太可能,但它突然出现在我身上,只是看着你的代码。
然而,在回答你的问题时 - 我认为上面代码中的一个不好的做法是重用XmlHttpRequest对象,特别是不要让生命周期完成或调用xhr.abort()
。这是一个不,我一会儿就藏起来了。这里讨论了它和网络上的各个地方。请注意,IE特别适用于重用xhr。请参阅http://ajaxian.com/archives/the-xmlhttprequest-reuse-dilemma。
希望这有帮助,
斯科特