Promiseを返す多くの非同期関数を持つ既存のプロジェクトがあります。非同期関数が同期的に完了し、可能であればこのコードをより短く/より良くしたい場合があるように、キャッシュを追加しています。
return $.Deferred(function(def) { def.resolve(); }).promise();
たとえば、次のようなほとんどのAJAXリクエストを処理するData Serviceクラスがあります。
function DataService() {
var self = this;
self.makeRequest = function(functionName, data) {
return $.Deferred(function(def) {
var jsonData = JSON.stringify(data);
$.ajax({
type: "POST",
url: "WebService.asmx/" + functionName,
data: jsonData,
contentType: "application/json; charset=utf-8",
dataType: "json",
error: function(xhr, status, error) {
var ex;
try {
ex = eval("(" + xhr.responseText + ")");
ex.message = ex.Message;
ex.Message = undefined;
} catch (ex2) {
ex = { message: "Invalid Response From Server:\r\n" + xhr.responseText };
}
if (ex.message == "LoginRequired") {
app.viewModels.main.loginRequired(true);
}
else {
app.showError(ex.message);
}
def.reject(ex.message);
}
});
}).promise();
}
}
次に、現在常にmakeRequestを呼び出す別のクラスの関数があります。
self.deleteMe = function()
{
return app.dataservice.makeRequest('deleteItem');
}
DeleteMe関数を更新して、常にmakeRequestを呼び出すのではなく、代わりに同期作業を行ってから戻るようにします。ただし、呼び出されたものはそれを期待するため、Promiseを返す必要がありますが、「すでに完了/解決済みのPromise」である必要があります。現在、私はそれを行うために上記のコードの最初のセットを使用しています。もっと良い方法があるに違いないようです。
@Eselk、
私の経験では、$.Deferred(function(def) {...});
の構築が必要になることはめったにありませんが、状況によっては非常に役立つと思います。
まず、:
_return $.Deferred(function(def) { def.resolve(); }).promise();
_
に簡素化されます:
_return $.Deferred().resolve().promise();
_
次に、DataService.makeRequest()
では、次のように.then()
を利用することで、明示的な_$.Deferred
_の必要性を回避できます。
_function DataService() {
var self = this;
self.makeRequest = function (functionName, data) {
return $.ajax({
type: "POST",
url: "WebService.asmx/" + functionName,
data: JSON.stringify(data),
contentType: "application/json; charset=utf-8",
dataType: "json"
}).then(null, function (xhr, status, error) {
var ex;
try {
ex = eval("(" + xhr.responseText + ")");
ex.message = ex.Message;
ex.Message = undefined;
} catch (ex2) {
ex = {
message: "Invalid Response From Server:\r\n" + xhr.responseText
};
}
if (ex.message == "LoginRequired") {
app.viewModels.main.loginRequired(true);
} else {
app.showError(ex.message);
}
return ex.message;
});
};
}
_
主な側面は次のとおりです。
$.ajax()
は、Promise互換のjqXHRオブジェクトを返します。これは(成功またはエラーで).then()
によって即座に処理され、変更されます。.then(null, ...)
-新しいプロミスが渡され、$.ajax()
によって返される元のプロミスと同じ値で解決されます。したがって、「完了」(つまり、ajaxの成功)状態では、.then()
は完全に透過的です。return ex.message;
_-新しいプロミスが渡され、_ex.message
_で拒否されます。ただし、nett効果は元のコードと同じである必要があります。IMHOの.then()
のチェーンは、$.Deferred()
コールバック内ですべてを設定するよりもかなりクリーンです。
ところで、 '。Message'がstatus
引数(または_xhr.status
_ ??)として直接表示されるように適切なHTTPヘッダーをサーバー側に設定することで、eval("(" + xhr.responseText + ")")
などの必要性を回避できる場合があります)失敗コールバックの。たとえば、PHPでは次のようになります。
_$message = "my custom message";
header("HTTP/1.1 421 $message");
exit(0);
_
ASPは同じ機能を提供します。
IIRC、4xxシリーズのステータスコードはすべてその役割を果たします。 421はたまたま特定の意味のないものです。
単にreturn $.when();
を使用して既に解決された約束を返します。
引数をまったく渡さない場合、jQuery.when()は解決されたプロミスを返します。
リファレンス:https://api.jquery.com/jquery.when/
注:
return $.when(undefined);
と同じです。これは、配列とapply
の使用を回避する次のかなりクールなトリックにつながります。可変数のプロミスが完了するのを待ちたい場合in parallelループでこのパターンを使用できます:
var promise; // Undefined is treated as an initial resolved promise by $.when
while (insomeloop){
promise = $.when(promise, newpromise);
}
次に、完了時に最終呼び出しを行います。
promise.then(function(){
// All done!
});
例えば.
var promise;$.when
var $elements = $('.some-elements');
$elements.each(function(){
var $element = $(this).fadeout();
promise = $.when(promise, $element.promise());
});
promise.then(function(){
// All promises completed!
});
欠点は軽微です:
when
を呼び出すたびに、以前のプロミスが新しいプロミスにラップされます。わずかなオーバーヘッドで、一連のプロミスを維持および評価する必要がなくなりました。