JSのマルチスレッドファイルローダー(jQuery)

こんにちは、同僚。 この記事では、JS(jQuery)で(サーバー負荷が制限された)マルチスレッドのファイルダウンローダーを作成した経験について説明します。



ごく最近、私は問題を抱えていました(解決策をあなたと共有したい):管理パネルで、一度に複数のファイルを選択してアップロードできるようにしました。 このタスクは簡単なことであり、難しくはないように見えますが、最終的には、アナログが見つからなかったため、私の解決策はかなり興味深く思えました。



ソリューションNo. 1


タスクは単純であり、そしてもちろん、多くのソリューションがすでに書かれているため、私はGoogleに助けを求めました。 しかし、検索では肯定的な結果が得られませんでした-提案されたソリューションのほとんどはFlashを使用しています(特定の理由により、このようなソリューションを使用できませんでした)。 自転車を組み立てる必要がありました。



決定番号2


タスクは緊急であったため、緊急の解決策が必要でした。 長い間、 複数の属性を入力フィールド(HTML5で使用可能)にねじ込んだとは思いません。



<form id='FilesupLoadForm'> <input type='file' id='fileinput' name='files' multiple="multiple" > <input type="submit" value='upload'> </form>
      
      







これに続いて、1つのファイルではなくファイルの配列を受信するようにハンドラーに小さな変更が加えられ、問題は解決されました! (私の素朴さ(未経験)は礼拝堂ではありませんでした)。

多くの人が既に笑って考えているように、500分の3が最初の通常のnginxファイルのバッチに答えました。 さらに考えなければなりませんでした。



決定3


過去の決定は管理者にとって美しく便利に行われたため、それに基づいて構築することが決定されました。 nginxが長いファイル処理のために返したエラーNo. 503の問題を解決する必要がありました。

考えてみると30分で新しいソリューションが表示されます。ajaxを一度にすべてのファイルではなく、1つずつ送信します。



解決策はおよそ次のとおりです。



 jQuery.each($('#fileinput')[0].files, function(i, f) { var file = new FormData(); file.append('file', f); $.ajax({ url: 'uploader.php', data: file, async : false, contentType: false, processData: false, dataType: "JSON", type: 'POST', beforeSend: function() {}, complete: function(event, request, settings) {}, success: function(data){ } }); });
      
      







すべてが単純です:ファイルの配列(目的の入力にある)を並べ替え、ファイルを操作するためのクラスのインスタンスを作成し(詳細は後述)、ajaxによってサーバーにリクエストを送信します。 「 async:false 」パラメーターに注意する価値があります。ここでは、ajaxリクエストの同期実行を設定します。非同期リクエストは多くのサーバーリクエストを作成するため、簡単に実行できます。

解決策は機能しますが、エラーはありませんが、問題が1つあります。動作が遅いです。 そして、私は問題の別の解決策のアイデアを思いつきました。



決定4


サーバーへのファイルのダウンロードを高速化するために、ファイルが転送されるリクエストの数を増やすことができます。 このような決定は、2つの問題を解決することにかかっています。

1)。たくさんのリクエストがあると、私はすぐに私のサーバーで地獄に行きます。

2)同時にダウンロードされる大量のファイルは、チャンネル全体を詰まらせます。

問題から判断すると、ローダーは実行中のリクエストの数と転送されたデータの量を考慮し、ある条件下では、一部のリクエストが終了し、他のリクエストが開始するのを待ちます。

コードに取りかかりましょう:



  FilesUploader = { dataArr : new Array(), fStek : new Array(), vStek : 0, deley : 100, debug : true, maxFilesSize : 1024*1024*10, maxThreads : 10,
      
      







凡例:

dataArr-送信するデータを含む配列。

fStek-再帰をさらに停止し、不完全な関数からメモリをクリアするために、ここにタイムアウト識別子を書き込みます。

vStek-呼び出されたスレッドの数。

deley-フローとボリュームをチェックする関数の再帰遅延。

debug-デバッグモード。 デバッグには必要ですが、この例ではすべての兆候を削除しました。

maxFilesSize-ダウンロードされるファイルの最大量

maxThreads-スレッドの最大数。



変数(特にfStekdeley )の明快さは、 問題の 2番目のFilesUploader.controller()関数によって導入されます。 それまでの間、クラスの初期化に移りましょう。



  run : function() { jQuery.each($('#fileinput')[0].files, function(i, f) { FilesUploader.dataArr.push(f); }); FilesUploader.controller(); },
      
      







この関数では、フォーム内のボタンのクリックイベントの処理がハングします。 関数の動作は簡単です。入力に入力されたファイル( jQuery.each )を調べ 、配列内の各レコードを追加( FilesUploader.dataArr.push(f) )します。 次に、システムの最も重要で複雑な部分であるコントローラーを呼び出します。



  controller : function() { FilesUploader.fStek.push(setTimeout(FilesUploader.controller, FilesUploader.deley)); if(FilesUploader.vStek>=this.maxThreads) { return; } item = FilesUploader.dataArr.pop(); if(item) { if(FilesUploader.maxFilesSize-item.size < 0) { FilesUploader.dataArr.push(item); return; } FilesUploader.maxFilesSize-=item.size; FilesUploader.vStek++; FilesUploader.worker(item); } else clearTimeout(FilesUploader.fStek.pop()); },
      
      







関数の最初の行では、同じ関数を非同期で(一定期間後に)呼び出し(つまり、再帰を作成)、呼び出された関数の識別子を変数に入れて、その実行を中断します。

次は、スレッドをチェックするための条件です。

配列( FilesUploader.dataArr.pop() )からファイルを受け取った後、その存在を確認します。

1.ファイルがない場合、呼び出された関数を識別子( clearTimeout(FilesUploader.fStek.pop()) )で「 強制終了」します。

2.ファイルが存在する場合、ダウンロードされたファイルの量を確認し、それを超える場合はファイルをスタックに戻し、関数を終了します。 item) )。



 worker : function(item) { var file = new FormData(); file.append('file', item); $.ajax({ url: 'uploader.php', data: file, contentType: false, processData: false, dataType: "JSON", type: 'POST', beforeSend: function() {}, complete: function(event, request, settings) { FilesUploader.maxFilesSize+=this.fileData.size; FilesUploader.vStek--; }, success: function(data){ } }); },
      
      







ajaxを使用してサーバーにファイルを送信するには、ファイルデータ(file.append())をその中のFormDataクラスのインスタンスに配置する必要があります。

次に、 $ .ajax関数を呼び出します。この関数は、サーバー上のローダーにファイルを転送します。 各リクエスト(完全な()関数)の完了時に、許容ボリュームを増やし、実行可能スレッドの数を減らす必要があります(これは、「 FilesUploader.maxFilesSize + = this.fileData.size 」および「 FilesUploader.vStek— 」行で行われます)。



最後の仕上げは、コンソール出力機能と閉じ括弧です。



  out : function(message) { if(console.log && this.debug) console.log(message); } }
      
      







それだけです-サーバーへのマルチスレッドアップロードファイルのクラスは準備ができています。 次に、サーバーの構成、許容されるスレッド数、同時にダウンロードされるファイルのボリュームに応じて、すでに設定しておく必要があります。



All Articles