我正在使用html5 filereader API在本地获取照片,而无需用户上传照片。
在支持它的浏览器中,我允许多个选择,因此我遍历所选文件并在每个文件上执行一项功能(TC.editor.renderSlide()),如下所示:
handlePhotoUploads: function(event) {
var self = this;
TC.dialog.destroy();
var files = event.target.files;
var count = files.length + TC.editor.cache.slides.length;
for (var i = 0, f; f = files[i]; i++) {
if (!f.type.match('image.*')) {
continue;
}
var reader = new FileReader();
var index = TC.editor.getNewSlidesIndex();
TC.editor.addNewSlide('photo', index);
reader.onload = (function(theFile) {
var slideindex = index;
return function(e) {
TC.editor.renderSlide(slideindex, e.target.result, 'internal', count);
};
})(f);
reader.readAsDataURL(f);
}
},
问题在于TC.editor.renderSlide()函数可能要花费大量时间来执行(执行 Canvas 和DOM操作),因此当处理8个左右的大型图像文件时,浏览器将锁定相当长的时间。在此期间,即使“处理gif”也停止了动画处理。
有什么方法可以确保每个reader.onload事件仅在前一个事件完成后才触发?这样,通过分别查看每次对TC.editor.renderSlide()的调用结果(而不是在处理所有内容时锁定浏览器的当前状态),可以为用户提供定期的进度更新
我尝试将简单的setTimeout添加到renderSlide()无济于事?
任何帮助或想法将不胜感激。
最佳答案
onload
事件按顺序触发,当前未处理另一个处理程序时不执行该处理程序(“JS是单线程”)。当您在处理程序中启动某些异步处理(超时,动画,文件加载)时,这当然不算在内。
在这种情况下,您将需要手动处理顺序处理。使用队列等待过程很容易,这些队列在一个完成时执行:
var waiting = [];
// …create many parallel loaders, and on each:
….onevent = execute;
function execute(e) {
if (waiting.active)
waiting.push(e);
else {
waiting.active = true
// do something that takes its time, supplying a
… function callback(ready) {
waiting.active = false;
if (waiting.length)
execute(waiting.shift()); // go on with next
}
}
}
但是,在我看来,不是
renderSlide
引起了问题,而是您同时实例化了这么多FileReader
。通过将for循环变成异步调用的“递归”函数,使它们开始依次加载文件:var files = […]
(function handle(i) {
if (i >= files.length) return;
// create loader
….onevent = function(e) {
// do processing, and then call
handle(i+1);
// or call that from another callback if you want to do async
// processing, like "renderSlide"
};
})(0);