JavaScriptの非同期に関してですが、
一度非同期のものを使ってしまうと、二度と同期処理に戻れない。
従って全ての後続の処理をコールバック関数にぶちこむしかない。
このコールバック地獄と一生向き合う言語です。
Promiseが導入されましたが、一生即時実行関数でネストしていくクソみたいな構文を避ける為に、
thenメソッドで繋いでネストを1段階で食い止めることだけが目的の構文&機能です。
なので非同期を使うと同期処理に戻れないという問題が解消されたわけではありません。
じゃあどうするねん、に関しては以下の3択
- 関数型プログラミングを覚える
- オブジェクト指向プログラミングのDIを使いこなす
- async/await構文で(見てくれだけ)同期的な記述を行う
因みに質問文の自己回答に関しては、
Promise.allはasync/awaitで再現出来ませんのでその使い方が大体正しいですが、
Promise.allがPromiseインスタンスの配列を要求する作りになっているので、
forEachではなくmapを使ってPromiseインスタンスの配列を用意するのがより綺麗な書き方になります。
ちょっと作って見ましょう。
JavaScript
1// Node.jsは各ファイルのスコープが区切られているので即時実行関数で包む必要はない
2const fs = require("fs");
3// requireは余程の事態で無い限りファイルの先頭でまとめて宣言すること
4const romanizer = require("romanizer");
5const romanize = romanizer.romanize.bind(romanizer);
6
7const tgtDir = process.argv[2];
8const files = fs.readdirSync(tgtDir);
9const promises = files.map(romanize);
10
11// Promiseの配列から結果の配列を取り出してから結合する作りにすべき
12Promise.all(promises).then(initials => {
13 // という訳でコードの通りに作ったヤツ
14 const initialLog = initials.map(romaji =>
15 romaji.toLowerCase().substr(0, 1)
16 ).join("\r\n");
17 console.log(initialLog);
18
19 // 改行後を出力するのが目的なら、これでよくね?
20 initials
21 .map(it => it.toLowerCase().substr(0, 1))
22 .forEach(it => console.log(it));
23});
ローマ字に変更するだけのシンプルな機能のモジュールと想定されるので、
別にPromise.allを使った並列実行にこだわる必要がなければ、
async/awaitで十分だと思います。
async/awaitはPromiseの糖衣構文ですので、
Promise以上の事は出来ませんがコード自体はかなり平易になります。
下記にコードを書いて見ましたが(ほとんど普通の)同期処理だ!わーい。
良ければ学習してみてください。
JavaScript
1const fs = require("fs");
2const romanizer = require("romanizer");
3
4const tgtDir = process.argv[2];
5const files = fs.readdirSync(tgtDir);
6
7const main = async () => {
8 let initialLog = "";
9 for (let file of files) {
10 const romaji = await romanizer.romanize(file)
11 const initial = romaji.toLowerCase().substr(0, 1);
12 initialLog += initial + "\r\n";
13 }
14 console.log(initialLog);
15}
16
17main();
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2019/05/13 07:53