0

ブログシステム用のファイルアップローダーを作成しようとしています。これにより、ユーザーはファイルをドロップするだけで、サーバーに自動的にアップロードされます。不思議なことに(私にとっては)、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);
    },
});
4

2 に答える 2

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]);

コールバックの外部で呼び出すと、画像の読み込みが終了したときではなく、画像の読み込みが開始された直後に実行されます。

明確にするために、すぐに画像を描きました。

説明

これを解決するには、次のように、ドロップされた画像の量と読み込みが完了した画像の量を比較します。

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);
    },
});
于 2013-01-03T08:39:14.347 に答える
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は最大で最後にロードされました。

于 2013-01-03T09:11:48.950 に答える