[解決済み] 既存のコールバックAPIをプロミスに変換するにはどうすればよいですか?
質問
プロミスを使いたいのですが、コールバックAPIは以下のような形式で用意されています。
1. DOMロードまたはその他の1回限りのイベント。
window.onload; // set to callback
...
window.onload = function() {
};
2. プレーンコールバック
function request(onChangeHandler) {
...
}
request(function() {
// change happened
...
});
3. ノードスタイルコールバック("nodeback")。
function getStuff(dat, callback) {
...
}
getStuff("dataParam", function(err, data) {
...
})
4. ノードスタイルコールバックによるライブラリ全体。
API;
API.one(function(err, data) {
API.two(function(err, data2) {
API.three(function(err, data3) {
...
});
});
});
プロミスでAPIを操作するには、どのように"promisify"すればよいのでしょうか?
解決方法を教えてください。
プロミスには状態があり、保留状態から始まり、解決することができます。
- 達成済み 計算が正常に終了したことを意味します。
- 却下 計算が失敗したことを意味します。
プロミスリターン関数
を投げてはいけません。
代わりに拒否を返さなければなりません。プロミスを返す関数から投げる場合、その関数の中で
} catch {
と
a
.catch
. プロミス化されたAPIを使っている人は、プロミスが投げることを期待していない。もしあなたがJSで非同期APIがどのように動作するかわからない場合 - お願いします。
この回答を見る
を最初に選択します。
1. DOMロードなどの1回限りのイベント。
つまり、データが利用可能であることを示すために、いつfulfilledまたはrejectedフェーズに移行するかということです。
.then
).
をサポートする最新のプロミス実装では
Promise
コンストラクタは、ネイティブのES6プロミスと同じです。
function load() {
return new Promise(function(resolve, reject) {
window.onload = resolve;
});
}
そして、出来上がったプロミスを次のように使うことになる。
load().then(function() {
// Do things after onload
});
deferredをサポートするライブラリで(ここでは例として$qを使用しますが、後でjQueryも使用します)。
function load() {
var d = $q.defer();
window.onload = function() { d.resolve(); };
return d.promise;
}
あるいはjQueryのようなAPIで、一度だけ起こるイベントにフックする。
function done() {
var d = $.Deferred();
$("#myObject").once("click",function() {
d.resolve();
});
return d.promise();
}
2. プレーンコールバック
これらのAPIは、JSではコールバックが一般的なので、わりとよく使われています。では、よくあるケースとして
onSuccess
と
onFail
:
function getUserData(userId, onLoad, onFail) { …
をサポートする最近のプロミス実装では
Promise
コンストラクタは、ネイティブのES6プロミスと同じです。
function getUserDataAsync(userId) {
return new Promise(function(resolve, reject) {
getUserData(userId, resolve, reject);
});
}
deferredをサポートするライブラリで(ここではこの例でjQueryを使ってみますが、上記では$qも使っています)。
function getUserDataAsync(userId) {
var d = $.Deferred();
getUserData(userId, function(res){ d.resolve(res); }, function(err){ d.reject(err); });
return d.promise();
}
また、jQueryは
$.Deferred(fn)
を非常によく模倣した式を書くことができるという利点があります。
new Promise(fn)
という形式で、以下のようになります。
function getUserDataAsync(userId) {
return $.Deferred(function(dfrd) {
getUserData(userId, dfrd.resolve, dfrd.reject);
}).promise();
}
注:ここでは、jQuery遅延の
resolve
と
reject
メソッドは、quot;detachable" つまり、それらは
インスタンス
jQuery.Deferred()を使用します。全てのLibがこの機能を提供しているわけではありません。
3. ノードスタイルコールバック("nodeback")。
ノードスタイルコールバック(nodebacks)は、コールバックが常に最後の引数で、その最初の引数がエラーになるという特殊な形式を持っています。まずは手動でプロミシングしてみましょう。
getStuff("dataParam", function(err, data) { …
へ。
function getStuffAsync(param) {
return new Promise(function(resolve, reject) {
getStuff(param, function(err, data) {
if (err !== null) reject(err);
else resolve(data);
});
});
}
遅延を使うと、次のようなことができます(この例ではQを使いますが、Qは新しい構文をサポートするようになりました)。 を選択する必要があります。 ):
function getStuffAsync(param) {
var d = Q.defer();
getStuff(param, function(err, data) {
if (err !== null) d.reject(err);
else d.resolve(data);
});
return d.promise;
}
一般的に、あまり手動でプロミスをするべきではありません。Node 8+ のネイティブプロミスと同様に Node を考慮して設計されたほとんどのプロミスライブラリは、ノードバックをプロミスするためのメソッドを内蔵しています。例えば
var getStuffAsync = Promise.promisify(getStuff); // Bluebird
var getStuffAsync = Q.denodeify(getStuff); // Q
var getStuffAsync = util.promisify(getStuff); // Native promises, node only
4. ノードスタイルコールバックによるライブラリ全体。
ここでは黄金律はなく、ひとつひとつプロミシングしていくのです。しかし、いくつかのプロミス実装では、これを一括して行うことができます。例えばBluebirdでは、ノードバックAPIをプロミスAPIに変換するのは以下のように簡単です。
Promise.promisifyAll(API);
または ネイティブプロミス で ノード :
const { promisify } = require('util');
const promiseAPI = Object.entries(API).map(([key, v]) => ({key, fn: promisify(v)}))
.reduce((o, p) => Object.assign(o, {[p.key]: p.fn}), {});
注意事項
-
の時はもちろん
.then
ハンドラでは、プロミスをする必要はありません。プロミスを返すのは.then
ハンドラは、そのプロミスの値で解決または拒否します。ハンドラから投げる.then
ハンドラも良い習慣で、プロミスを拒否します。これが有名なプロミススローの安全性です。 -
実際の
onload
の場合はaddEventListener
よりもonX
.
関連
-
[解決済み】Node Version Manager のインストール - nvm コマンドが見つかりません。
-
[解決済み】awaitは非同期関数でのみ有効です。
-
[解決済み] 配列から特定の項目を削除するにはどうすればよいですか?
-
[解決済み] jQueryで要素が非表示になっているかどうかを確認するには?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] JavaScriptで文字列をbooleanに変換するにはどうしたらいいですか?
-
[解決済み] コールバック内で正しい `this` にアクセスする方法
-
[解決済み】別のウェブページにリダイレクトするにはどうすればいいですか?
-
[解決済み】PromiseとObservablesの違いは何ですか?
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
JSアレイループと効率解析の比較
-
Vueはランニングライト形式のテキストを水平方向にスクロールする機能を実装している
-
JavaScriptのクロージャの説明
-
vueのプロジェクトでモックを使用する方法を知っていますか?
-
Vueのイベント処理とイベントモディファイアの解説
-
Vueのフィルタの説明
-
[解決済み】Node.jsで "Cannot find module "エラーを解決するには?
-
[解決済み】Node.js Error: Cannot find module express
-
[解決済み】JavaScriptでインラインIF文の書き方は?
-
[解決済み】React Uncaught Error: 対象コンテナが DOM 要素でない [重複]。