Javascript 有没有办法让多个html5 filereader.onload事件按顺序启动?

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 =

我使用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()函数可能需要花费大量时间来执行(执行画布和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()函数分解。结果非常灵敏,完全符合预期。谢谢大家。:)嘿,我还没完成我的回答:-)很高兴能帮上忙,我刚刚看到你的编辑!:)当我意识到哪里出了错的时候,我马上开始重新编码。。。在不到一分钟的时间内完成了,这是多么不同啊!你现在的答案非常棒,尽管代码因我个人应用程序的特定结构而有所不同,但与我采取的方法基本相同。非常感谢!