2017-01-25 6 views
2

私は単一の<input>タグで複数の画像をアップロードできるフィールドを持つフォームを持っています。 Nodeを使ってファイルシステムにアクセスすると、非同期にファイルを読み書きするためのコールバックがキューに入れられているようです。私は複数のファイルを持っているので、私はforループ内にこれらの呼び出しを持っているので、iの値は、コールバックがヒットした時点で常にarray.lengthの値になり、オブジェクトが未定義になります。ノードで複数のファイルをアップロードすると、同期コールバックが強制的に実行されますか?

for (var i = 0; i < req.files.photos.length; i++) { 
    req.fs.readFile(req.files.photos[i].path, function(err, data) { 
     if(err) throw err; 

     // i = req.files.photos.length here 
     // Test is undefined when the breakpoint on this line is hit for the first time 
     var test = req.files.photos[i]; 

     // Both print "undefined" 
     console.log(test.name); 
     console.log(test.originalFileName); 

     var newPath = __dirname + "/../public/uploads/" + req.files.photos[i].name; 

     req.fs.writeFile(newPath, data, function (err) { 
      if (err) throw err; 

      console.log("it worked"); 
     }); 
    }); 
} 

答えて

1

for (var i = 0; i < req.files.photos.length; i++) { 
    (function(j) { 
     req.fs.readFile(req.files.photos[j].path, function(err, data) { 
      if(err) throw err; 
      var test = req.files.photos[j]; 

      console.log(test.name); 
      console.log(test.originalFileName); 

      var newPath = __dirname + "/../public/uploads/" + req.files.photos[j].name; 

      req.fs.writeFile(newPath, data, function (err) { 
       if (err) throw err; 
       console.log("it worked"); 
      }); 
     }); 
    }(i)); 
} 

すぐにこの機能を呼び出すことによって、iの値になりますiはプリミティブ値なので、現在の値でキャプチャされ、ファンクション内に新しい参照(j)として格納されます。これは、スコープチェーンとクロージャの構文の古典的な例です。問題がまだ残っている場合は、さらに多くの例がオンラインにあります

+1

ありがとう、これで問題は解決しました。私はこれらの前に私はajaxで非同期の問題を抱えていたとき、私はこれを次の時間に念頭に置いておくべきだと思います:) – James

0

最も簡単な方法は、実際に約束してasync/awaitに切り替えることです。両方を同時に行う必要がある場合は、Promise.allを使用することができます。

async/awaitで約束したりセットアップしたりするのに少し時間がかかりますが、100%の価値があります。

import pify from 'pify'; 
import {readFile, writeFile} from 'fs'; 

const readFilePr = pify(readFile); 
const writeFilePr = pify(writeFile); 

async function copyFiles(req) { 
const {photos} = req.files; 

    for (let photo of photos) { 
    try { 
     const image = await readFilePr(photo.path); 
     const newPath = `${__dirname}/../public/uploads/${photo.name}`; 
     await writeFilePr(newPath);  
    } catch (e) { 
     console.error("Problem copying download: ",e); 
    }  
    } 
} 

あなたは(私はそれをテストしていない、何のタイプミスか何かがないと仮定した場合)動作するようにそのコードのすべてにbabelを設定する必要があるかもしれません。あなたは、forループの各反復中iの正しい値をキャプチャするために生命維持(すぐに呼び出される関数式)を使用することができます

関連する問題