下面是使用 JavaScript 中的 HTTP 请求预加载文件并将其保存到浏览器缓存的代码。问题是,如果没有您的帮助,我无法找到跟踪 preloadMe
函数中的错误的解决方案:)
我知道我们可以将 onerror
添加到 preloadOne
并且它工作正常:
xhr.onerror = function() {
console.log('onerror happend');
};
但我想知道我们如何在 preloadMe
函数中做到这一点,例如 oncomplete
、 onfetched
和 onprogress
。像这样的东西:
preload.onerror = items => {
console.log('onerror happend'); // onerror here
}
非常感谢任何评论或修改...
这是迄今为止我的代码:
(function(global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.Preload = factory());
}(this, (function() {
'use strict';
function preloadOne(url, done) {
const xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.responseType = 'blob';
xhr.onprogress = event => {
if (!event.lengthComputable) return false
let item = this.getItemByUrl(event.target.responseURL);
item.completion = parseInt((event.loaded / event.total) * 100);
item.downloaded = event.loaded;
item.total = event.total;
this.updateProgressBar(item);
};
xhr.onload = event => {
let type = event.target.response.type;
let blob = new Blob([event.target.response], {
type: type
});
let url = URL.createObjectURL(blob);
let responseURL = event.target.responseURL;
let item = this.getItemByUrl(responseURL);
item.blobUrl = url;
item.fileName = responseURL.substring(responseURL.lastIndexOf('/') + 1);
item.type = type;
item.size = blob.size;
done(item);
};
xhr.send();
}
function updateProgressBar(item) {
var sumCompletion = 0;
var maxCompletion = this.status.length * 100;
for (var itemStatus of this.status) {
if (itemStatus.completion) {
sumCompletion += itemStatus.completion;
}
}
var totalCompletion = parseInt((sumCompletion / maxCompletion) * 100);
if (!isNaN(totalCompletion)) {
this.onprogress({
progress: totalCompletion,
item: item
});
}
}
function getItemByUrl(rawUrl) {
for (var item of this.status) {
if (item.url == rawUrl) return item
}
}
function fetch(list) {
return new Promise((resolve, reject) => {
this.loaded = list.length;
for (let item of list) {
this.onerror(item); // onerror here
this.status.push({
url: item
});
this.preloadOne(item, item => {
this.onfetched(item);
this.loaded--;
if (this.loaded == 0) {
this.oncomplete(this.status);
resolve(this.status);
}
});
}
});
}
function Preload() {
return {
status: [],
loaded: false,
onprogress: () => {},
oncomplete: () => {},
onfetched: () => {},
onerror: () => {}, // onerror here
fetch,
updateProgressBar,
preloadOne,
getItemByUrl
}
}
return Preload;
})));
//preload here
preloadMe();
function preloadMe() {
const preload = Preload();
preload.fetch([
'https://round-arm-authority.000webhostapp.com/Ultimate%20Video%20Hack/videos/vid1.mp4'
]).then(items => {
// use either a promise or 'oncomplete'
console.log(items);
});
preload.oncomplete = items => {
console.log(items);
}
preload.onerror = items => {
console.log('onerror happend'); // onerror here
}
preload.onprogress = event => {
console.log(event.progress + '%');
}
preload.onfetched = item => {
console.log(item);
}
};
最佳答案
有几个选项。您可以将错误回调添加为参数,就像使用 done
回调所做的那样。
如果您想让错误回调可选,您可以这样做:
function preloadOne(url, done, error) {
const xhr = new XML HttpRequest();
// ...
if(typeof error === 'function') xhr.onerror = error;
// ...
}
在某些方面,这可能更可取,因为您可以在调用 xhr.send()
之前注册错误处理程序。 (虽然我不知道这是否重要,但我不确定事件循环在这方面是如何工作的。)
另一种方法是在 preloadOne
函数末尾返回 xhr
,如下所示:
function preloadOne(url, done) {
const xhr = new XMLHttpRequest();
// ...
xhr.send();
return xhr;
}
然后您可以轻松地添加自己的事件处理程序:
var preload = preloadOne('https://my.site.com/path', x=> {
console.log('done');
});
preload.onerror = function(event) {
console.log('error');
};
编辑:return xhr
解决方案的事件循环注意事项。
经过一些研究,我相信如果在 xhr.send()
之后添加事件监听器,可能会丢失错误事件。这是基于MDN event loop页面,特别是添加消息
部分,其中显示:
In web browsers, messages are added anytime an event occurs and there is an event listener attached to it. If there is no listener, the event is lost.
因此,虽然在 JavaScript 堆栈为空之前消息不会得到处理,但 XHR 错误的消息排队几乎随时都可能发生。或者如果尚未附加处理程序,则尝试排队。
但是,如果您确实想返回xhr
并确保附加事件处理程序的机会,我相信有一种方法可以做到这一点,通过更改preoloadOne
将 xhr.send
放入 setTimeout
中。
setTimeout(()=> xhr.send(), 0);
这会将 send
扔到事件队列中,这意味着它必须等待 JavaScript 调用堆栈清空,然后进入事件循环的下一个周期。当调用堆栈清空时,应附加所有错误事件处理程序。
关于javascript - 将 onerror 函数添加到 XMLHttpRequest,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60174852/