[解決済み] Node.jsやJavascriptで非同期関数呼び出しを同期関数にラップする方法とは?
質問
ある関数を公開するライブラリをメンテナンスしているとします。
getData
. ユーザーは実際のデータを取得するためにそれを呼び出します。
var output = getData();
裏側ではデータはファイルに保存されているので、実装した
getData
を使用して、Node.js 組み込みの
fs.readFileSync
. これは明らかに
getData
と
fs.readFileSync
は同期関数です。ある日、基礎となるデータソースをMongoDBのような非同期でしかアクセスできないリポジトリに変更するように言われました。また、ユーザーを怒らせないようにするように言われました。
getData
APIは、単なるプロミスを返したり、コールバックパラメータを要求するように変更することはできません。どのようにして両方の要件を満たすのでしょうか?
コールバック/プロミスを使った非同期関数は、JavasSriptやNode.jsのDNAです。どんな非自明な JS アプリでも、おそらくこのコーディング スタイルが浸透しています。しかし、このやり方は、いわゆる「コールバックのピラミッド」と呼ばれる破滅的な状況に陥りやすい。さらに悪いことに、コールチェーン内の呼び出し側のコードが非同期関数の結果に依存している場合、それらのコードもコールバック関数でラップしなければならず、呼び出し側にコーディングスタイルの制約を課してしまいます。私は時々、大規模なグローバルリファクタリングを避けるために、非同期関数(多くの場合サードパーティライブラリで提供される)を同期関数にカプセル化する必要性を感じることがあります。このテーマで解決策を探すと、大抵は ノード ファイバー またはそれに由来する npm パッケージに行き着きます。しかし、Fibers は私が直面している問題を解決することができません。Fibers の作者が提供した例でも、その欠陥が示されています。
...
Fiber(function() {
console.log('wait... ' + new Date);
sleep(1000);
console.log('ok... ' + new Date);
}).run();
console.log('back in main');
実際の出力です。
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
back in main
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
関数Fiberが本当に非同期関数sleepを同期に変えるのであれば、出力はこうなるはずです。
wait... Fri Jan 21 2011 22:42:04 GMT+0900 (JST)
ok... Fri Jan 21 2011 22:42:05 GMT+0900 (JST)
back in main
もう一つ簡単な例を JSFiddle を作成し、期待される出力を得るためのコードを探しています。私はNode.jsでのみ動作するソリューションを受け入れるので、JSFiddleで動作しないにもかかわらず、任意のnpmパッケージを必要とする自由があります。
どのように解決するのですか?
デシンク は非同期関数を同期に変換します。JavaScriptレイヤーでNode.jsのイベントループを呼び出すことによって、ブロッキング機構で実装されています。その結果、deasyncはスレッド全体をブロックすることなく、後続のコードの実行をブロックするだけで、ビジーウェイトを発生させることもありません。このモジュールで、jsFiddleの課題に対する答えがあります。
function AnticipatedSyncFunction(){
var ret;
setTimeout(function(){
ret = "hello";
},3000);
while(ret === undefined) {
require('deasync').runLoopOnce();
}
return ret;
}
var output = AnticipatedSyncFunction();
//expected: output=hello (after waiting for 3 sec)
console.log("output="+output);
//actual: output=hello (after waiting for 3 sec)
(免責事項: 私は共著者である
deasync
. モジュールはこの質問を投稿した後に作成されましたが、実行可能な提案は見つかりませんでした)。
関連
-
nullのプロパティinnerHTMLを読み取れません エラーメッセージ
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] JavaScriptでメールアドレスを検証するのに最適な方法は何ですか?
-
[解決済み] JavaScriptでタイムスタンプを取得する方法は?
-
[解決済み] JavaScriptのオブジェクトが空であることをテストするにはどうすればよいですか?
-
[解決済み] 配列に特定のインデックスで項目を挿入する方法 (JavaScript)
-
[解決済み] Node.jsのプログラムにコマンドライン引数を渡すにはどうしたらいいですか?
-
[解決済み] Node.jsを使うタイミングをどう判断するか?
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Vueはランニングライト形式のテキストを水平方向にスクロールする機能を実装している
-
JavaScriptのクロージャの説明
-
vueにおけるv-forループオブジェクトのプロパティ
-
Vueでルートネスティングを実装する例
-
Vueのフォームイベントのデータバインディングの説明
-
[解決済み】「X-Frame-Options」を「SAMEORIGIN」に設定したため、フレームでの表示を拒否された。
-
[解決済み】TypeErrorの解決方法。未定義またはヌルをオブジェクトに変換できない
-
[解決済み】リクエストに失敗していないのに、「TypeError: failed to fetch」が表示される。
-
JavaScriptのStringに関する共通メソッド
-
[解決済み】Node.jsはなぜシングルスレッドなのですか?[クローズド]