2016-10-26 10 views
1

よくある質問だと思いますが、具体的には状況は次のとおりです。
私はmammothモジュールを使用して、docxファイルをhtmlに変換します。モジュールはpromiseを返します。
私はファイルの配列を持っており、すべてのファイルに対して約束を作成するためにループを使用すると、どのファイルが処理されたかを知るために何らかの約束が結果を返す必要があります。約束のループ。どのように約束が結果を返すのかを検出する方法は?

for(var i=0;i<filesPaths.length;i++){ 
    mammoth.convertToHtml({path: filesPaths[i]}) 
     .then(function(result){ 
      filesHtml.push(result.value); 
      //here I need to know the value of filesPaths[i] 
     }) 
} 

答えて

2

質問を書いている間、答えは明白になりました(多くの場合そうです:)。
プロミスを自己呼び出し関数でラップし、関連する情報をローカル変数に格納することができます。代替とあなた自身の答えに対応するために

for(var i=0;i<filesPaths.length;i++){ 
    (function(){ 
    var fileName = filesPaths[i]; //or any other information related to promise 
    mammoth.convertToHtml({path: filesPaths[i]}) 
     .then(function(result){ 
      filesHtml.push({ 
       text:result.value, 
       fileName:fileName 
         }); 

     }) 
    })() 
} 
0

ループ内の関数を作成するには素晴らしいアイデアではない、それが作成した関数の未知の数にかなり良い方法です。 forEachループを使用した場合、コールバック関数で同じカプセル化が行われます。

var arr = ['a', 'b', 'c']; 

function prom(thing) { 
    return Promise.resolve(thing); 
} 

for (var i = 0; i < arr.length; i++) { 
    prom(arr[i]).then(function(val){ 
     console.log(`for: got val ${val} with arr[${i}]`); 
    }); 
} 
// Logs: 
// "for: got val a with arr[3]" 
// "for: got val b with arr[3]" 
// "for: got val c with arr[3]" 

arr.forEach(function(val, index) { 
    prom(val).then(function(val){ 
     console.log(`forEach: got val ${val} with arr[${index}]`); 
    });  
}); 
// Logs: 
// "forEach: got val a with arr[0]" 
// "forEach: got val b with arr[1]" 
// "forEach: got val c with arr[2]"  
1

あなたは()(多くの関数呼び出しの面であなたのソリューションのようなものですが、少しクリーナー)アレイ法.MAP使用することができます。

filesPaths.map(function(fileName, i){ 
    mammoth.convertToHtml({path: fileName}) 
    .then(/* ... */) 
    ; 
}); 
// Here filesHtml is empty and you don't know when will be filled!! 

...汚れている(参照最後のコメント)。

それとも、単にPromise.allは()の結果を収集するために使用することができます。

var P = Promise.all(
    filesPaths.map(function(fileName){ 
    return mammoth.convertToHtml({path: fileName}); 
    }) 
).then(function(resultArr){ 
    return Promise.all(resultArr.map(function(result, i){ 
    return { 
     text: text.value, 
     fileName: filesPaths[i], 
    }; 
    })); 
}).then(function(filesHtml){ 
    /* Here you know filesHtml is fully filled */ 
}); 

P.then(function(filesHtml){ 
    /* ...and here too */ 
}); 

この方法で、あなたはまた、グローバル(またはそれ以上の範囲)の変数を持つものをいじっていません。

+0

あなたの最初の解決策は本当にきれいです。そして、私は '.forEach()'と '.map()'を使う方が良い(クリーナー)と思います。すべての約束事がいつ処理されるのか分からないというあなたのコメントについて、私はこれにカウンタを使用します。 'Promise.all'に関しては、' promiseのいずれかが拒否された場合、全てのPromiseは、拒否された約束の価値を即座に拒否し、それが解決したかどうかにかかわらず、他の約束をすべて捨てるからです。モジュールがいずれかのファイルを変換できない場合、すべてのファイルは変換されません。 – s976

+0

私はあなたがチェックできるわけではありません。明らかにループすることができます(他の非同期作業を処理する機会がないため、タイムアウトまたは他の非同期アプローチを使用します)。私はこれがただちにではなく、あなたは手でそれを扱うべきであることを単に意味します。拒否については、いくつかのエラーコードを価値として解決した約束に切り替えることや、簡単に破棄することは自明です。 – bitifet

+0

...そのアプローチの唯一の本当の欠点(私は簡潔さのために省略した)は、そのような結果を伴ういくらかのハード処理が必要な場合は、それを開始する前にすべてのファイルが変換されるのを待っています。それ以外の場合は、残りのファイルが変換されている間に非同期で実行できます。しかし、それはあなたのケースではないようです... – bitifet