3つの関数を順番に実行するには、どのように呼び出す必要がありますか?


151

この関数を次々と呼び出す必要がある場合は、

$('#art1').animate({'width':'1000px'},1000);        
$('#art2').animate({'width':'1000px'},1000);        
$('#art3').animate({'width':'1000px'},1000);        

私はjQueryで次のようなことができることを知っています:

$('#art1').animate({'width':'1000px'},1000,'linear',function(){
    $('#art2').animate({'width':'1000px'},1000,'linear',function(){
        $('#art3').animate({'width':'1000px'},1000);        
    });        
});        

しかし、jQueryを使用しておらず、呼び出したいとしましょう。

some_3secs_function(some_value);        
some_5secs_function(some_value);        
some_8secs_function(some_value);        

どのように私は実行するために、この関数を呼び出す必要がありsome_3secs_function、そのコールが終了した後、その後、実行some_5secs_functionし、そのコールが終了した後、コールsome_8secs_function

更新:

これはまだ機能しません:

(function(callback){
    $('#art1').animate({'width':'1000px'},1000);
    callback();
})((function(callback2){
    $('#art2').animate({'width':'1000px'},1000);
    callback2();
})(function(){
    $('#art3').animate({'width':'1000px'},1000);
}));

3つのアニメーションが同時に開始します

私の間違いはどこですか?


関数が正確に3 5&8秒で呼び出されるのか、それとも次々と呼び出されるのですか?
Trass Vasston、2011

私は考えてあなたが同期対非同期関数の実行に関する単にわかりません。以下の回答を更新しました。それが役に立てば幸い。
ウェイン

これを試してください。github.com
dineshkani24

回答:


243

JavaScriptでは、ある同期非同期の機能が。

同期関数

JavaScriptのほとんどの関数は同期です。複数の同期関数を続けて呼び出す場合

doSomething();
doSomethingElse();
doSomethingUsefulThisTime();

それらは順番に実行されます。doSomethingElsedoSomething完了するまで開始しません。doSomethingUsefulThisTimeは、doSomethingElseが完了するまで開始されません。

非同期関数

ただし、非同期関数は互いに待機しません。上記と同じコードサンプルを見てみましょう。今回は、関数が非同期であると仮定しています。

doSomething();
doSomethingElse();
doSomethingUsefulThisTime();

関数は順番に初期化されますが、すべてほぼ同時に実行されます。どれが最初に終了するかを一貫して予測することはできません。実行に最も短い時間がかかるものが最初に終了します。

ただし、非同期の関数を順番に実行したい場合もあれば、同期の関数を非同期に実行したい場合もあります。幸いにも、これはそれぞれコールバックとタイムアウトで可能です。

コールバック

のは、私たちは順番に実行することを、我々は3つの非同期の機能を持っていると仮定しましょうsome_3secs_functionsome_5secs_functionsome_8secs_function

JavaScriptでは引数として関数を渡すことができるため、関数が完了した後に実行するコールバックとして関数を渡すことができます。

このような関数を作成すると

function some_3secs_function(value, callback){
  //do stuff
  callback();
}

その後、次のように順番に呼び出すことができます:

some_3secs_function(some_value, function() {
  some_5secs_function(other_value, function() {
    some_8secs_function(third_value, function() {
      //All three functions have completed, in order.
    });
  });
});

タイムアウト

JavaScriptでは、特定のタイムアウト(ミリ秒単位)後に実行するように関数に指示できます。これにより、事実上、同期関数を非同期で動作させることができます。

3つの同期関数がある場合は、setTimeout関数を使用して非同期に実行できます。

setTimeout(doSomething, 10);
setTimeout(doSomethingElse, 10);
setTimeout(doSomethingUsefulThisTime, 10);

ただし、これは少し見苦しく、DRYの原則[ウィキペディア]に違反しています。関数の配列とタイムアウトを受け入れる関数を作成することで、これを少し整理できます。

function executeAsynchronously(functions, timeout) {
  for(var i = 0; i < functions.length; i++) {
    setTimeout(functions[i], timeout);
  }
}

これは次のように呼び出すことができます:

executeAsynchronously(
    [doSomething, doSomethingElse, doSomethingUsefulThisTime], 10);

要約すると、同期的に実行したい非同期関数がある場合はコールバックを使用し、非同期に実行したい同期関数がある場合はタイムアウトを使用します。


7
これは、例に示されているように、3、5、8秒間関数を遅延させず、次々に実行されるだけです。
Trass Vasston、2011

1
@ピーター-待って、私は混乱しています。これらが完了までに数秒かかる単純な同期呼び出しである場合、なぜこれが必要なのでしょうか。
ウェイン

9
@Peter-+1は、3つの同期関数を順番に呼び出すためにこれまでに見た中で最も美しい複雑なメソッドです。
ウェイン

4
非同期と同期js関数の違いを巧みに説明していただきありがとうございます。これはとても説明しています。
jnelson 2014年

2
これは、次の理由で正しくありません。(1)3つのタイムアウトはすべて10秒後に解決されるため、3つのラインすべてが同時にトリガーされます。(2)この方法では、チェーン内の以前の非同期関数が解決してそれがトリガーになるのを待つのではなく、事前に期間を把握し、「スケジュール」機能が将来発生するようにする必要があります。---代わりに、コールバック、プロミス、または非同期ライブラリのいずれかを使用して、次の回答のいずれかを使用します。
zeroasterisk 2017

37

この回答ではpromisesECMAScript 6標準のJavaScript機能であるを使用しています。ターゲットプラットフォームがサポートしていない場合はpromises、PromiseJsでポリフィルします。

ここで私の答えを見てください。アニメーションを使用する場合は、アニメーション付きの関数が完了するまで待ってから、別の関数を実行してくださいjQuery

とを使用したコードは次のようにES6 PromisesなりjQuery animationsます。

Promise.resolve($('#art1').animate({ 'width': '1000px' }, 1000).promise()).then(function(){
    return Promise.resolve($('#art2').animate({ 'width': '1000px' }, 1000).promise());
}).then(function(){
    return Promise.resolve($('#art3').animate({ 'width': '1000px' }, 1000).promise());
});

通常のメソッドもでラップできPromisesます。

new Promise(function(fulfill, reject){
    //do something for 5 seconds
    fulfill(result);
}).then(function(result){
    return new Promise(function(fulfill, reject){
        //do something for 5 seconds
        fulfill(result);
    });
}).then(function(result){
    return new Promise(function(fulfill, reject){
        //do something for 8 seconds
        fulfill(result);
    });
}).then(function(result){
    //do something with the result
});

thenこの方法は、できるだけ早くとして実行されPromise、完成。通常、function渡されたの戻り値はthen結果として次の戻り値に渡されます。

ただし、a Promiseが返された場合、次のthen関数Promiseは実行が完了するまで待機し、その結果(に渡される値)を受け取りfulfillます。


私はこれが役に立つことを知っていますが、いくつかのコンテキストを与えるために実際の例を探すことなくコードを理解するのは難しいことがわかりました。私はYouTubeでこの動画を見つけました:youtube.com/watch ? v=y5mltEaQxa0-動画のソースをここに書きましたdrive.google.com/file/d/1NrsAYs1oaxXw0kv9hz7a6LjtOEb6x7z-/…でキャッチのようないくつかのニュアンスが不足していますこれを詳しく説明するこの例。(getPostById()行で別のIDを使用するか、投稿の名前と一致しないように著者の名前を変更してみてください)
JGFMK

20

同期関数と非同期関数の実行の違いを十分に理解していないようです。

更新で提供したコードは、各コールバック関数をすぐに実行し、コールバック関数はすぐにアニメーションを開始します。ただし、アニメーションは非同期で実行されます。それはこのように動作します:

  1. アニメーションのステップを実行する
  2. setTimeout次のアニメーションステップと遅延を含む関数で呼び出す
  3. 時間が経つ
  4. setTimeout実行に与えられたコールバック
  5. ステップ1に戻る

これは、アニメーションの最後のステップが完了するまで続きます。それまでの間、同期関数はずっと前に完了しています。つまり、animate関数の呼び出しに実際に3秒かかりません。効果は遅延とコールバックでシミュレートされます。

必要なのはキューです。内部的には、jQueryのは唯一の実行、アニメーションをキューにあなたを対応するアニメーションが完了したコールバックを。コールバックが別のアニメーションを開始する場合、効果はそれらが順番に実行されることです。

最も単純なケースでは、これは次と同等です。

window.setTimeout(function() {
    alert("!");
    // set another timeout once the first completes
    window.setTimeout(function() {
        alert("!!");
    }, 1000);
}, 3000); // longer, but first

これが一般的な非同期ループ関数です。指定された関数を順番に呼び出し、それぞれの間で指定された秒数待機します。

function loop() {
    var args = arguments;
    if (args.length <= 0)
        return;
    (function chain(i) {
        if (i >= args.length || typeof args[i] !== 'function')
            return;
        window.setTimeout(function() {
            args[i]();
            chain(i + 1);
        }, 2000);
    })(0);
}    

使用法:

loop(
  function() { alert("sam"); }, 
  function() { alert("sue"); });

明らかにこれを変更して、構成可能な待機時間を取るか、最初の関数をすぐに実行するか、チェーン内の関数が戻ったとき、falseまたはapply指定されたコンテキストまたはその他の必要な関数に戻るときに実行を停止することができます。


14

私は非同期ライブラリがこれを行う非常にエレガントな方法を提供すると信じています。promiseとcallbackは少し難しい場合がありますが、asyncは、思考プロセスを合理化するためのきちんとしたパターンを提供できます。関数をシリアルで実行するには、それらを非同期ウォーターフォールに配置する必要があります。非同期の専門用語では、すべての関数は、taskいくつかの引数とaを取るaと呼ばれcallbackます。これはシーケンスの次の関数です。基本的な構造は次のようになります。

async.waterfall([
  // A list of functions
  function(callback){
      // Function no. 1 in sequence
      callback(null, arg);
  },
  function(arg, callback){
      // Function no. 2 in sequence
      callback(null);
  }
],    
function(err, results){
   // Optional final callback will get results for all prior functions
});

ここで構造を簡単に説明しようとしました。詳細については、ウォーターフォールガイドを読んでください。かなりよく書かれています。


1
これにより、JSはもう少し我慢できるようになります。
2018年

9

関数は、終了時に呼び出されるコールバック関数を取る必要があります。

function fone(callback){
...do something...
callback.apply(this,[]);

}

function ftwo(callback){
...do something...
callback.apply(this,[]);
}

次に、使用法は次のようになります:

fone(function(){
  ftwo(function(){
   ..ftwo done...
  })
});

4
asec=1000; 

setTimeout('some_3secs_function("somevalue")',asec*3);
setTimeout('some_5secs_function("somevalue")',asec*5);
setTimeout('some_8secs_function("somevalue")',asec*8);

ここではsetTimeoutの詳細については触れませんが、

  • この場合、文字列として実行するコードを追加しました。これは、varをsetTimeout-ed関数に渡す最も簡単な方法ですが、純粋主義者は不満を言うでしょう。
  • 引用符なしで関数名を渡すこともできますが、変数を渡すことはできません。
  • コードはsetTimeoutのトリガーを待機しません。
  • これは最初は頭を動かすのが難しい場合があります。前のポイントのため、呼び出し元の関数から変数を渡すと、タイムアウトがトリガーするまでにその変数は存在しなくなります-呼び出し元の関数が実行され、 vars gone。
  • 私はこれをすべて回避するために匿名関数を使用することが知られていますが、もっと良い方法があるでしょう。

3

あなたはそれをjavascriptでタグ付けしたので、あなたの関数名は3、5、8秒なのでタイマーコントロールを使います。タイマーを開始し、3秒後に最初に呼び出し、5秒目に2番目に呼び出し、8秒目に3番目に呼び出し、それが終わったらタイマーを停止します。

通常、Javascriptでは、関数が正しいものを次々に実行しますが、時限アニメーションを実行しようとしているように見えるため、タイマーが最善の策です。


2

//sample01
(function(_){_[0]()})([
	function(){$('#art1').animate({'width':'10px'},100,this[1].bind(this))},
	function(){$('#art2').animate({'width':'10px'},100,this[2].bind(this))},
	function(){$('#art3').animate({'width':'10px'},100)},
])

//sample02
(function(_){_.next=function(){_[++_.i].apply(_,arguments)},_[_.i=0]()})([
	function(){$('#art1').animate({'width':'10px'},100,this.next)},
	function(){$('#art2').animate({'width':'10px'},100,this.next)},
	function(){$('#art3').animate({'width':'10px'},100)},
]);

//sample03
(function(_){_.next=function(){return _[++_.i].bind(_)},_[_.i=0]()})([
	function(){$('#art1').animate({'width':'10px'},100,this.next())},
	function(){$('#art2').animate({'width':'10px'},100,this.next())},
	function(){$('#art3').animate({'width':'10px'},100)},
]);


これは何ですか?下線には何がバインドされていますか?に割り当てられた機能は何をしnextますか?
mtso 2017

1
jsfiddleを使用してサンプル2を説明します。 jsfiddle.net/mzsteyuy/3 おおまかに説明してもらえれば、サンプル2はjsfiddleのコードの短い方法です。下線は、要素が対抗できる配列(i)であり、関数nextおよび関数[0]〜[2]です。
yuuya 2017

1

この方法でpromiseを使用することもできます。

    some_3secs_function(this.some_value).then(function(){
       some_5secs_function(this.some_other_value).then(function(){
          some_8secs_function(this.some_other_other_value);
       });
    });

あなたは作る必要があります some_value.then内からアクセスするグローバルにする必要があります。

または、次のように、外部関数から内部関数が使用する値を返すこともできます。

    one(some_value).then(function(return_of_one){
       two(return_of_one).then(function(return_of_two){
          three(return_of_two);
       });
    });

0

JavaScriptのsetTimeoutに基づく「waitUntil」関数を使用します

/*
    funcCond : function to call to check whether a condition is true
    readyAction : function to call when the condition was true
    checkInterval : interval to poll <optional>
    timeout : timeout until the setTimeout should stop polling (not 100% accurate. It was accurate enough for my code, but if you need exact milliseconds, please refrain from using Date <optional>
    timeoutfunc : function to call on timeout <optional>
*/
function waitUntil(funcCond, readyAction, checkInterval, timeout, timeoutfunc) {
    if (checkInterval == null) {
        checkInterval = 100; // checkinterval of 100ms by default
    }
    var start = +new Date(); // use the + to convert it to a number immediatly
    if (timeout == null) {
        timeout = Number.POSITIVE_INFINITY; // no timeout by default
    }
    var checkFunc = function() {
        var end = +new Date(); // rough timeout estimations by default

        if (end-start > timeout) {
            if (timeoutfunc){ // if timeout function was defined
                timeoutfunc(); // call timeout function
            }
        } else {
            if(funcCond()) { // if condition was met
                readyAction(); // perform ready action function
            } else {
                setTimeout(checkFunc, checkInterval); // else re-iterate
            }
        }
    };
    checkFunc(); // start check function initially
};

これは、関数が特定の条件をtrueに設定すると完全に機能し、ポーリングできるようになります。さらに、タイムアウトが付属しており、関数が何かの時間に失敗した場合の代替手段を提供します(時間範囲内であっても。ユーザーのフィードバックについて考えてください!)

例えば

doSomething();
waitUntil(function() { return doSomething_value===1;}, doSomethingElse);
waitUntil(function() { return doSomethingElse_value===1;}, doSomethingUseful);

ノート

日付により、おおよそのタイムアウトが推定されます。より正確にするには、console.time()などの関数に切り替えます。Dateはクロスブラウザとレガシーサポートを強化していることに注意してください。正確なミリ秒単位の測定が必要ない場合。気にしないでください、または代わりにラップして、ブラウザーがサポートしている場合はconsole.time()を提供してください


0

メソッド1をメソッド2、3、4の後に実行する必要がある場合、次のコードスニペットは、JavaScriptでDeferredオブジェクトを使用してこれを解決することができます。

function method1(){
  var dfd = new $.Deferred();
     setTimeout(function(){
     console.log("Inside Method - 1"); 
     method2(dfd);	 
    }, 5000);
  return dfd.promise();
}

function method2(dfd){
  setTimeout(function(){
   console.log("Inside Method - 2"); 
   method3(dfd);	
  }, 3000);
}

function method3(dfd){
  setTimeout(function(){
   console.log("Inside Method - 3"); 	
   dfd.resolve();
  }, 3000);
}

function method4(){   
   console.log("Inside Method - 4"); 	
}

var call = method1();

$.when(call).then(function(cb){
  method4();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.