2017-01-29 7 views
0

私は複数の非同期呼び出しを達成しようとしており、すべてが終了したときだけ続行しようとしています。Promise.all()は、約束が配列される前に発生します

プロセスがこのようなもので、私はそれがこの順序で行わ必要があります。 ファイルパスのリストを取得し、 は、 は、 は、サムネイルを作成し、ビットマップを変換する一括挿入するために、アレイに情報を追加し、新たな目的地にそれらをコピーしますDBへ

私は約束事とPromise.all()メソッドの配列を使用しています。このメソッドは、promise配列が(完全に)まだ埋め込まれていないときに実行されるため、早すぎます。 forループの後にある程度の遅延があっても動作しますが、必要な時間はファイル数によって異なります。ここで

は、メインの呼び出しです:

queueFiles(files).then(function() { 
    // Add to DB 
    console.log(current_import.sql.length); // Number of all datasets (0 at runtime) 
    console.log(current_import.sql);  // An array of datasets ([] at runtime) 
}); 

これは期待通りに動作しない機能である:

let import_promises = { 
    copy_promises : [], 
    convert_promises : [], 
    thumbnail_promises : [], 
    sql_promises : [] 
}; 

function queueFiles(files) { 
    return new Promise(function (resolve, reject) { 
     try { 
      for (file of files) { 
       let original_filename = file.split("\\").pop(); 
       let original_extension = original_filename.split(".").pop(); 

       let hashed_name = crypto.createHmac('sha256', secret).update(original_filename).digest('hex') + "." + original_extension; 
       let new_path = data_folder + "/" + hashed_name; 

       import_promises.copy_promises.push(fs.copy(file, new_path).then(function() { 
        if (original_extension == "bmp") { 
         import_promises.convert_promises.push(convertFile(new_path).then(function (result) { 
          import_promises.thumbnail_promises.push(createThumbnail(result.path, thumb_folder + "/" + result.path.split("/").pop(), 500).then(function() { 
           import_promises.sql_promises.push(addSql(result.data)); 
          })); 
         })); 
        } else { 
         import_promises.thumbnail_promises.push(createThumbnail(new_path, thumb_folder + "/" + hashed_name, 500).then(function() { 
          import_promises.sql_promises.push(addSql(new_path)); 
         })); 
        } 
       })); 
      } 

      Promise.all([import_promises.copy_promises, import_promises.convert_promises, import_promises.thumbnail_promises, import_promises.sql_promises]) 
       .then(() => { 
        // All files copied, converted, thumbnails created and prepared to insert into DB 
        resolve(); 
       }); 
     } 
     catch (err) { 
      reject(err); 
     } 
    }); 
} 

そして、これらは、ヘルパー関数です:

function createThumbnail(input, output, width) { 
    return new Promise(function (resolve, reject) { 
     try { 
      gm(input) 
       .scale(width) 
       .write(output, function (err) { 
        if (err) { 
         throw(err); 
        } 
        resolve(); 
       }); 
     } 
     catch (err) { 
      reject(err); 
     } 
    }); 
} 

function convertFile(newPath) { 
    return new Promise(function (resolve, reject) { 
     try { 
      let convertedPath = newPath.replace(/\.[^/.]+$/, "") + ".png"; 

      execFile("convert", [newPath, convertedPath]).then(function() { 
       fs.unlinkSync(newPath); 
       resolve({path: convertedPath}); 
      }); 
     } 
     catch (err) { 
      reject(err); 
     } 
    }); 
} 

function addSql(data) { 
    return new Promise(function (resolve, reject) { 
     try { 
      current_import.sql.push(data); 

      current_import.done++; 
      updateProgressBar(); 

      resolve(); 
     } 
     catch (err) { 
      reject(err); 
     } 
    }); 
} 

編集済みコード(有効):

function createThumbnail(input, output, width) { 
    return new Promise(function (resolve, reject) { 
     gm(input) 
      .scale(width) 
      .write(output, function (err) { 
       if (err) { 
        return reject(err); 
       } 
       resolve(); 
      }); 
    }); 
} 

function convertFile(newPath) { 
    let convertedPath = newPath.replace(/\.[^/.]+$/, "") + ".png"; 

    return execFile("convert", [newPath, convertedPath]).then(function() { 
     fs.unlinkSync(newPath); 
     return convertedPath; 
    }); 
} 

function addSql(data) { 
    current_import.sql.push(data); 

    current_import.done++; 
    updateProgressBar(); 
} 

function queueFiles(files) { 
    return Promise.all(files.map(function (file) { 
     let original_filename = file.split("\\").pop(); 
     let original_extension = original_filename.split(".").pop(); 

     let hashed_name = crypto.createHmac('sha256', secret).update(original_filename).digest('hex') + "." + original_extension; 
     let new_path = data_folder + "/" + hashed_name; 

     return fs.copy(file, new_path).then(function() { 
      if (original_extension == "bmp") { 
       return convertFile(new_path) 
        .then(function (path) { 
         return {path: path, hash: path.split("/").pop()}; 
        }); 
      } else { 
       return {path: new_path, hash: hashed_name} 
      } 
     }).then(function (result) { 
      let outPath = thumb_folder + "/" + result.hash; 
      return createThumbnail(result.path, outPath, 500) 
       .then(function() { 
        return outPath; 
       }); 
     }).then(function (thumb_path) { 
      return addSql(thumb_path); 
     }); 
    })); 
} 
+1

使用して 'このような新しい約束はしばしば[反パターン]です(http://stackoverflow.com/q/23803743) – Frxstrem

答えて

0

まず、convertFilesqueueFilesプロミスコンストラクタ

は必要ありませんが、問題はimport_promises.sql_promisesが約束の配列で、import_promises.copy_promisesは約束の配列です...で、import_promises.convert_promisesは約束の配列です。 ...そう、あなたが約束の配列の配列にPromise.allを実行している... Promise.allは期待していた約束

chnage

Promise.all([import_promises.copy_promises, import_promises.convert_promises, import_promises.thumbnail_promises, import_promises.sql_promises]).then ... 
の配列anipatterns用として

Promise.all([].concat(import_promises.copy_promises, import_promises.convert_promises, import_promises.thumbnail_promises, import_promises.sql_promises).then ... 

から

converFilesは単に

function convertFile(newPath) { 
    let convertedPath = newPath.replace(/\.[^/.]+$/, "") + ".png"; 

    return execFile("convert", [newPath, convertedPath]).then(function() { 
     fs.unlinkSync(newPath); 
     resolve({path: convertedPath}); 
    }); 
} 

addsqlすることができても、非同期ではないので、なぜそれは約束は謎です返す -

とqueueFiles(そこに他のいくつかの問題を深く見ないで)

function queueFiles(files) { 
    for (file of files) { 
     let original_filename = file.split("\\").pop(); 
     let original_extension = original_filename.split(".").pop(); 

     let hashed_name = crypto.createHmac('sha256', secret).update(original_filename).digest('hex') + "." + original_extension; 
     let new_path = data_folder + "/" + hashed_name; 

     import_promises.copy_promises.push(fs.copy(file, new_path).then(function() { 
      if (original_extension == "bmp") { 
       import_promises.convert_promises.push(convertFile(new_path).then(function (result) { 
        import_promises.thumbnail_promises.push(createThumbnail(result.path, thumb_folder + "/" + result.path.split("/").pop(), 500).then(function() { 
         import_promises.sql_promises.push(addSql(result.data)); 
        })); 
       })); 
      } else { 
       import_promises.thumbnail_promises.push(createThumbnail(new_path, thumb_folder + "/" + hashed_name, 500).then(function() { 
        import_promises.sql_promises.push(addSql(new_path)); 
       })); 
      } 
     })); 
    } 

    return Promise.all([import_promises.copy_promises, import_promises.convert_promises, import_promises.thumbnail_promises, import_promises.sql_promises]); 
} 

流れの意味を理解しようとした後、私はこれを作ってみた、それは約束した理由を、私は理解していない部分のみが、addSql機能である、

function convertFile(newPath) { 
    return execFile("convert", [newPath, convertedPath]).then(function() { 
     fs.unlinkSync(newPath); 
     return convertedPath; 
    }); 
} 

function createThumbnail(input, output, width) { 
    return new Promise(function(resolve, reject) { 
     gm(input) 
     .scale(width) 
     .write(output, function (err) { 
      if (err) { 
       return reject(err); 
      } 
      resolve(); 
     }); 
    }); 
} 

function addSql(data) { 
    current_import.sql.push(data); 

    current_import.done++; 
    updateProgressBar(); 
} 

function queueFiles(files) { 
    return Promise.all(files.map(function(file) { 
     return fs.copy(file, new_path).then(function() { 
      if (original_extension == "bmp") { 
       return convertFile(new_path) 
       .then(function(path) { 
        return {path: path, hash: path.split("/").pop()}; 
       }); 
      } else { 
       return {path: new_path, hash: hashed_name} 
      } 
     }).then(function (result) { 
      return createThumbnail(result.path, thumb_folder + "/" + result.hash, 500) 
      .then(function() { 
       return result.path; 
      }); 
     }).then(function(result) { 
      return addSql(result); 
     }); 

    })); 
} 
+0

ありがとう。この変更では、空の配列の即時結果は得られませんが、データの一部だけが残っています。 convertFilesメソッドとqueueFilesメソッドの変更方法もわかりません。私はプロミスを作成する代わりに関数呼び出しを返すべきですか? – pedroheeenriqu

+0

私はちょうど答えを編集しました...戻り値がプッシュされた関数をプッシュして配列の迷路を... ....あなたが待つ必要があるものを見つけようとするのは私の頭です。約束の最も良い機能の1つ、それは連鎖です –

+0

私は約束を新しく、それらを利用してコードを構造化する方法を学びます。私は単に私の質問に記載されている順序を必要とします。ファイルを変換するには、最初にファイルをコピーする必要があります。サムネイルを作成するにはまず変換する必要があります。サムネイルを含む情報を配列に挿入することができます。 – pedroheeenriqu

関連する問題