[解決済み】ネイティブXHRをプロミス化する方法は?
質問
私はフロントエンドアプリで(ネイティブ)プロミスを使用してXHRリクエストを実行したいのですが、巨大なフレームワークのおふざけは一切ありません。
xhrがプロミスを返すようにしたいのですが、これはうまくいきません。
Uncaught TypeError: Promise resolver undefined is not a function
)
function makeXHRRequest (method, url, done) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function() { return new Promise().resolve(); };
xhr.onerror = function() { return new Promise().reject(); };
xhr.send();
}
makeXHRRequest('GET', 'http://example.com')
.then(function (datums) {
console.log(datums);
});
解決方法は?
ネイティブなXHRリクエストを作成する方法を知っていると仮定します。 ここで と こちら )
以来
ネイティブプロミスをサポートするすべてのブラウザ
をサポートします。
xhr.onload
であれば、すべての
onReadyStateChange
のようなおふざけです。 一歩下がって、コールバックを使った基本的なXHRリクエスト関数から始めてみましょう。
function makeRequest (method, url, done) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function () {
done(null, xhr.response);
};
xhr.onerror = function () {
done(xhr.response);
};
xhr.send();
}
// And we'd call it as such:
makeRequest('GET', 'http://example.com', function (err, datums) {
if (err) { throw err; }
console.log(datums);
});
万歳! これは非常に複雑なこと(カスタムヘッダーやPOSTデータなど)ではなく、前進するのに十分なものです。
プロミスのコンストラクタ
このようにプロミスを構築することができます。
new Promise(function (resolve, reject) {
// Do some Async stuff
// call resolve if it succeeded
// reject if it failed
});
プロミスのコンストラクタは、2つの引数を渡される関数(ここでは
resolve
と
reject
). これらはコールバックと考えることができ、1つは成功したとき、もう1つは失敗したときです。 例はすごいですね、更新してみましょう
makeRequest
このコンストラクタで
function makeRequest (method, url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject({
status: xhr.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function () {
reject({
status: xhr.status,
statusText: xhr.statusText
});
};
xhr.send();
});
}
// Example:
makeRequest('GET', 'http://example.com')
.then(function (datums) {
console.log(datums);
})
.catch(function (err) {
console.error('Augh, there was an error!', err.statusText);
});
今、私たちはプロミスの力を利用し、複数のXHRの呼び出しを連鎖させることができます(そして、その連鎖は
.catch
は、いずれかの呼び出しでエラーが発生した場合にトリガーされます)。
makeRequest('GET', 'http://example.com')
.then(function (datums) {
return makeRequest('GET', datums.url);
})
.then(function (moreDatums) {
console.log(moreDatums);
})
.catch(function (err) {
console.error('Augh, there was an error!', err.statusText);
});
これをさらに改良して、POST/PUT パラメータとカスタムヘッダの両方を追加することができます。 複数の引数の代わりにオプションオブジェクトを使用し、そのシグネチャを使用しましょう。
{
method: String,
url: String,
params: String | Object,
headers: Object
}
makeRequest
は、次のようになります。
function makeRequest (opts) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(opts.method, opts.url);
xhr.onload = function () {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr.response);
} else {
reject({
status: xhr.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function () {
reject({
status: xhr.status,
statusText: xhr.statusText
});
};
if (opts.headers) {
Object.keys(opts.headers).forEach(function (key) {
xhr.setRequestHeader(key, opts.headers[key]);
});
}
var params = opts.params;
// We'll need to stringify if we've been given an object
// If we have a string, this is skipped.
if (params && typeof params === 'object') {
params = Object.keys(params).map(function (key) {
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');
}
xhr.send(params);
});
}
// Headers and params are optional
makeRequest({
method: 'GET',
url: 'http://example.com'
})
.then(function (datums) {
return makeRequest({
method: 'POST',
url: datums.url,
params: {
score: 9001
},
headers: {
'X-Subliminal-Message': 'Upvote-this-answer'
}
});
})
.catch(function (err) {
console.error('Augh, there was an error!', err.statusText);
});
より包括的なアプローチは、以下のサイトで見ることができます。 MDN .
関連
-
[解決済み】Javascriptのコールバック関数がFirefoxで「Callback is not a function」というエラーを投げる
-
[解決済み] React with ES7: Uncaught TypeError: Cannot read property 'state' of undefined [duplicate] (未定義のプロパティ'state'を読み込むことはできません。
-
[解決済み】React、Uncaught ReferenceError。ReactDOMは定義されていません
-
[解決済み] 配列から特定の項目を削除するにはどうすればよいですか?
-
[解決済み] jQueryで要素が非表示になっているかどうかを確認するには?
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] あるJavaScriptファイルを他のJavaScriptファイルにインクルードするにはどうすればよいですか?
-
[解決済み] GUID / UUIDの作成方法
-
[解決済み】別のウェブページにリダイレクトするにはどうすればいいですか?
-
[解決済み】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 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】 Uncaught TypeError: data.push is not a function
-
[解決済み] Uncaught Invariant Violation: 前のレンダリング中よりも多くのフックをレンダリングした
-
[解決済み】webpack-dev-serverにリモート接続すると、「Invalid Host header」というメッセージが表示されます。
-
[解決済み】XMLHttpRequestモジュールが定義されていない/見つからない
-
[解決済み】Javascriptのコールバック関数がFirefoxで「Callback is not a function」というエラーを投げる
-
[解決済み】リソースはドキュメントと解釈されるが、MIMEタイプはapplication/zipで転送される
-
[解決済み】WebSocket接続に失敗しました。WebSocket のハンドシェイク中にエラーが発生しました。予期しない応答コードです。400
-
[解決済み】Uncaught ReferenceError。Firebase は定義されていません。
-
[解決済み】TypeError:res.jsonは関数ではありません。
-
[解決済み】ETIMEDOUTエラーの対処方法は?