Javascript 有没有办法让多个html5 filereader.onload事件按顺序启动?
我使用html5 filereader API在本地获取照片,用户无需上传照片 在支持它的浏览器中,我允许多个选择,因此我在所选文件中循环,并对每个文件(TC.editor.renderSlide())执行一个函数,如下所示:Javascript 有没有办法让多个html5 filereader.onload事件按顺序启动?,javascript,Javascript,我使用html5 filereader API在本地获取照片,用户无需上传照片 在支持它的浏览器中,我允许多个选择,因此我在所选文件中循环,并对每个文件(TC.editor.renderSlide())执行一个函数,如下所示: handlePhotoUploads: function(event) { var self = this; TC.dialog.destroy(); var files = event.target.files; var count =
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()函数可能需要花费大量时间来执行(执行画布和DOM操作),因此在处理8个左右的大型图像文件时,浏览器会被锁定相当长的时间。在此期间,即使“处理gif”也会停止动画制作
有没有办法确保每个reader.onload事件仅在前一个事件完成后激发?这样,用户可以通过单独查看每次调用TC.editor.renderSlide()的结果,而不是在处理所有内容时锁定浏览器的当前情况,定期获得进度更新
我尝试过在renderSlide()中添加一个简单的setTimeout,但没有成功
任何帮助或想法都将不胜感激。活动按顺序进行。Javascript是单线程的,因此当其中一个事件处理程序正在执行时,不会触发其他事件,而且浏览器*
保持无响应状态,因为它的单线程被运行Javascript事件处理程序占用。在setTimeout
中执行整个renderSlide()
是不够的,因为浏览器在整个renderSlide()执行期间仍将被锁定。您需要将renderSlide()
中的实际逻辑分解为单独的块,每个块都可以使用setTimeout(chunk,1)
延迟,从而给浏览器一点喘息的空间来保持响应
*
实际上,锁定的可能不是整个浏览器,可能只是一个选项卡或一组相关选项卡在单个线程中运行。实际的浏览器架构有所不同。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
s。通过将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);
不要使用for
循环
。从load
回调中开始处理下一个文件。感谢这里的一切真的。。。Ianzz和Felix建议说,我实际上已经做到了和你一样。我已使读取器调用递归,并用setTimeout将renderSlide()函数分解。结果非常灵敏,完全符合预期。谢谢大家。:)嘿,我还没完成我的回答:-)很高兴能帮上忙,我刚刚看到你的编辑!:)当我意识到哪里出了错的时候,我马上开始重新编码。。。在不到一分钟的时间内完成了,这是多么不同啊!你现在的答案非常棒,尽管代码因我个人应用程序的特定结构而有所不同,但与我采取的方法基本相同。非常感谢!