同期方式で行う必要がある3つのHTTP呼び出しがあり、1つの呼び出しから別の呼び出しにデータを渡す方法を教えてください。
function first()
{
ajax()
}
function second()
{
ajax()
}
function third()
{
ajax()
}
function main()
{
first().then(second).then(third)
}
2つの関数に遅延を使用しようとしましたが、部分的な解決策を思い付きました。 3つの機能のために拡張できますか?
function first() {
var deferred = $.Deferred();
$.ajax({
"success": function (resp)
{
deferred.resolve(resp);
},
});
return deferred.promise();
}
function second(foo) {
$.ajax({
"success": function (resp)
{
},
"error": function (resp)
{
}
});
}
first().then(function(foo){second(foo)})
いずれの場合も、$.ajax()
によって返されるjqXHRオブジェクトを返します。
これらのオブジェクトはPromiseと互換性があるため、.then()
/.done()
/.fail()
/.always()
とチェーン化できます。
.then()
は、質問の場合とまったく同じように、この場合に必要なものです。
function first() {
return $.ajax(...);
}
function second(data, textStatus, jqXHR) {
return $.ajax(...);
}
function third(data, textStatus, jqXHR) {
return $.ajax(...);
}
function main() {
first().then(second).then(third);
}
引数data
、textStatus
およびjqXHR
は、前の関数の$.ajax()
呼び出しから発生します。 first()
フィードsecond()
およびsecond()
フィードthird()
。
DEMO($.when('foo')
の代わりに、履行された約束を果たすために$.ajax(...)
を使用) 。
JQueryでpromiseを使用する場合、実際にははるかに簡単なアプローチがあります。以下をご覧ください。
$.when(
$.ajax("/first/call"),
$.ajax("/second/call"),
$.ajax("/third/call")
)
.done(function(first_call, second_call, third_call){
//do something
})
.fail(function(){
//handle errors
});
すべての呼び出しを$ .when(...)呼び出しにチェーンし、.done(...)呼び出しで戻り値を処理するだけです。
ご希望の場合のウォークスルーは次のとおりです。 http://collaboradev.com/2014/01/27/understanding-javascript-promises-in-jquery/
返事はかなり遅れていますが、答えには連鎖のための簡単なコードが欠けていると思います。 jqueryでpromiseがサポートされているため、イベントのチェーンは非常に簡単です。チェーンには次のものを使用します。
$.ajax()
.then(function(){
return $.ajax() //second ajax call
})
.then(function(){
return $.ajax() //third ajax call
})
.done(function(resp){
//handle final response here
})
それは単純で、複雑なforループや複数のネストされたコールバックはありません。
それよりもずっと簡単です。
$.ajax
はすでにpromise(遅延オブジェクト)を返しますので、次のように書くことができます。
function first() {
return $.ajax(...);
}
より機能的な方法でそれを書くことができます:
[function() { return ajax(...)}, function(data) { return ajax(...)}]
.reduce(function(chain, callback) {
if(chain) {
return chain.then(function(data) { return callback(data); });
} else {
return callback();
}
}, null)
ここで見栄えの良い解決策を見つけました: jQuery 1.8.xで一連の遅延関数を連鎖させるにはどうすればよいですか?
そして、これは私自身の同様のアプローチの実装で、ややいですが、おそらく動作しています。返されたpromiseオブジェクトで"progress update"として各メソッドの結果をブロードキャストします。
$.chain = function() {
var defer = $.Deferred();
var funcs = arguments;
var left = funcs.length;
function next(lastResult) {
if(left == 0) {
defer.resolve();
return;
}
var func = funcs[funcs.length - left]; // current func
var prom = func(lastResult).promise(); // for promise will return itself,
// for jquery ojbect will return promise.
// these handlers will be launched in order we specify them
prom.always(function() {
left--;
}).done(function(ret) {
defer.notify({
idx: funcs.length-left,
left: left,
result: ret,
success: true,
});
}).fail(function(ret) {
defer.notify({
idx: funcs.length-left,
left: left,
result: ret,
success: false,
});
}).always(function(ret) {
next(ret);
});
}
next();
return defer.promise();
};
状況に合わせてどのように使用しますか?たぶんきれいではないかもしれませんが、うまくいくはずです:
function first() {
return ajax(...);
}
var id;
funciton second() {
return ajax(id, ...);
}
function third() {
return ajax(id, ...);
}
$.chain(first, second, third).progress(function(p) {
if(p.func == first)
id = p.result.identifier;
}).then(function() {
alert('everything is done');
});
または、first
関数からそのid変数を割り当てることができます。
または、前の関数の結果のみが必要な場合は、このアプローチを使用できます。
function first() {
return ajax(...);
}
function second(first_ret) {
return ajax(first_ret.id, ...);
}
function third(second_ret) {
return ajax(second_ret.something, ...);
}
以下は機能しているように見え、関数のリストを動的にすることができます。
<html>
<head>
<title>demo chained synchronous calls</title>
</head>
<body>
<script src="http://code.jquery.com/jquery-2.2.4.min.js"></script>
<script type="text/javascript">
function one(parms) {
console.log('func one ' + parms);
return 1;
}
function two(parms) {
console.log('func two ' + parms);
return 2;
}
function three(parms) {
console.log('func three ' + parms);
return 3;
}
function four(parms) {
console.log('func four ' + parms);
return 4;
}
var funcs = ['one', 'two', 'three', 'four'];
var rvals = [0];
function call_next_func() {
if (funcs.length == 0) {
console.log('done');
} else {
var funcname = funcs.shift();
console.log(funcname);
rvals.Push(window[funcname](rvals));
call_next_func();
}
}
$(document).ready(function($){
call_next_func();
});
</script>
</body>
</html>
これを行う最良の方法は、これのために再利用可能な関数を作成することです。これは、reduce
を使用する1行のコードでも実行できます。
function chainPromises(list) {
return list.reduce((chain, func) => chain ? chain.then(func) : func(), null);
}
この関数は、3つの関数のように、promiseオブジェクトを返すコールバックの配列を受け入れます。
使用例:
chainPromises([first, second, third]).then(function (result) {
console.log('All done! ', result);
});
このようにfirst
の結果も自動的にsecond
のパラメーターになるため、基本的には次のようになります。
first().then(function(res1) { return second(res1) })
.then(function(res2) { return third(res2) })
.then(function(result) { console.log('All done! ', result) });
そしてもちろん、必要なだけ関数を配列に追加できます。