JavaScript意外异步

时间:2013-01-03 08:32:15

标签: javascript jquery file-upload asynchronous

我正在尝试为我的博客系统制作一个文件上传器,它只会让用户在其中删除文件,它会自动将它们上传到服务器。奇怪的是(对我来说),console.log在填充之前输出dataArray,在超时后调用它会正确输出。

例如,如果我在放置区域放下4个文件,我会得到这个:

[]
[file1, file2, file3, file4]

然后我删除4个文件而不上传/刷新,我得到:

[file1, file2, file3, file4]
[file1, file2, file3, file4, file5, file6, file7, file8]

所以我的脚本出于某种原因异步工作?有人能告诉我这里我做错了吗?

var dataArray    = [];

$('.dropArea').bind(
{
    drop: function(e)
    {
        e.stopPropagation();
        e.preventDefault();
        var files = e.dataTransfer.files;

        $.each(files, function(index, file)
        {
            var fileReader = new FileReader();

            fileReader.onload = (function(file)
            {
                return function(e)
                {
                    var image = this.result;

                    dataArray.push({
                        name : file.name,
                        value: image
                    });
                }
            })(files[index]);

            fileReader.readAsDataURL(file);
        });

                    console.log(dataArray);
        setTimeout(function() { console.log(dataArray) }, 1000);
    },
});

2 个答案:

答案 0 :(得分:1)

你应该在回调中console.log()

fileReader.onload = (function(file)
{
    return function(e)
    {
        var image = this.result;

        dataArray.push({
            name : file.name,
            value: image
        });

        console.log(dataArray);
    }
})(files[index]);

如果您在回调之外调用它,它将在图像开始加载后立即运行,而不是在图像完成加载时立即运行。

我已经快速绘制了一张图片以供澄清:

description

您可以通过比较丢弃的图像数量和完成加载的图像数量来解决此问题,如下所示:

var dataArray    = [];
var count = 0; // amount of files dropped
var ready = 0; // amount of files finished loading

$('.dropArea').bind(
{
    drop: function(e)
    {
        ...

        $.each(files, function(index, file)
        {
            count++; // we start handling a file here so we increment

            ...

            fileReader.onload = (function(file)
            {
                return function(e)
                {
                    ...

                    ready++; // this image has finished loading so we increment
                }
            })(files[index]);
        });

        setTimeout(function() {
            if(ready === count) {
                // all images have been loaded
                console.log(dataArray);
            }
        }, 1000);
    },
});

答案 1 :(得分:0)

正如@Tim S.回答的那样,当启动加载时会触发onload事件,并且根据文件大小可能需要一些时间。以下是我解决所有文件是否已加载的问题。

drop: function(e)
    {
        e.stopPropagation();
        e.preventDefault();
        var files = e.dataTransfer.files;
        console.log(files.length + " queued for upload");

        var counter = 0;
        var loaded = 0;
        $.each(files, function(index, file)
        {
            counter++;
            console.log("File #"+counter+" loading started.")
            if (!files[index].type.match('image.*'))
            {
                $('.dropArea').html(message.error.onlyImage);
                errorMessage++;
            }
            var fileReader = new FileReader();

            fileReader.onload = (function(file, count)
            {
                return function(e)
                {
                    var image = this.result;

                    dataArray.push({
                        name : file.name,
                        value: image
                    });

                    loaded++;
                    console.log("File #"+count+" loaded.");

                    if (loaded == files.length) {
                        console.log("Loading finished!");
                    }
                }
            })(files[index], counter);

            fileReader.readAsDataURL(file);
        });
    }

实际上,控制台日志输出如下所示:

4 queued for upload 9a840a0_part_2_dragndrop_2.js:25
File #1 loading started. 9a840a0_part_2_dragndrop_2.js:32
File #2 loading started. 9a840a0_part_2_dragndrop_2.js:32
File #3 loading started. 9a840a0_part_2_dragndrop_2.js:32
File #4 loading started. 9a840a0_part_2_dragndrop_2.js:32
File #2 loaded. 9a840a0_part_2_dragndrop_2.js:52
File #4 loaded. 9a840a0_part_2_dragndrop_2.js:52
File #3 loaded. 9a840a0_part_2_dragndrop_2.js:52
File #1 loaded. 9a840a0_part_2_dragndrop_2.js:52
Loading finished! 

可以看出,文件#2首先被加载,因为它是最小的,而#1最后加载,而它是最大的。