70

クラス、イベント ハンドラー、およびコールバックを含むかなり複雑な回答しか見つかりませんでした (これは、やや大ハンマーのアプローチのように思えます)。コールバックは役に立つかもしれないと思いますが、最も単純なコンテキストではこれらを適用できないようです。次の例を参照してください。

<html>
  <head>
    <script type="text/javascript">
      function myfunction()  {
        longfunctionfirst();
        shortfunctionsecond();
      }

      function longfunctionfirst() {
        setTimeout('alert("first function finished");',3000);
      }

      function shortfunctionsecond() {
        setTimeout('alert("second function finished");',200);
      }
    </script>
  </head>
  <body>
    <a href="#" onclick="javascript:myfunction();return false;">Call my function</a>
  </body>
</html>

この場合、2 番目の関数は最初の関数の前に完了します。最初の関数が完了するまで 2 番目の関数の実行を強制的に遅らせる最も簡単な方法 (または 1 つある?) は何ですか?

- -編集 - -

これはくだらない例でしたが、David Hedlund のおかげで、この新しい例で実際に同期していることがわかります (テスト プロセスでブラウザがクラッシュしました!):

<html>
<head>

<script type="text/javascript">
function myfunction() {
    longfunctionfirst();
    shortfunctionsecond();
}

function longfunctionfirst() {
    var j = 10000;
    for (var i=0; i<j; i++) {
        document.body.innerHTML += i;
    }
    alert("first function finished");
}

function shortfunctionsecond() {
    var j = 10;
    for (var i=0; i<j; i++) {
        document.body.innerHTML += i;
    }
    alert("second function finished");
}
</script>

</head>

<body>
  <a href="#" onclick="javascript:myfunction();return false;">Call my function</a>
</body>
</html>

私の実際の問題はjQueryとIEにあったので、自分でどこにも行けない場合は、それについて別の質問を投稿する必要があります!

4

10 に答える 10

48

まあ、setTimeoutその定義によれば、スレッドを保持しません。これは望ましいことです。そうすると、待機している間、UI 全体がフリーズするからです。本当に を使用する必要がある場合はsetTimeout、コールバック関数を使用する必要があります。

function myfunction() {
    longfunctionfirst(shortfunctionsecond);
}

function longfunctionfirst(callback) {
    setTimeout(function() {
        alert('first function finished');
        if(typeof callback == 'function')
            callback();
    }, 3000);
};

function shortfunctionsecond() {
    setTimeout('alert("second function finished");', 200);
};

を使用していないsetTimeoutが、非常に長時間実行される関数がありsetTimeout、それをシミュレートするために を使用している場合、関数実際には同期的であり、この問題はまったくありません。setTimeoutただし、AJAX 要求は非同期であり、終了するまで UI スレッドを保持しないことに注意してください。AJAX では、 と同様にsetTimeout、コールバックを使用する必要があります。

于 2009-12-07T10:43:58.770 に答える
12

私はプログラミングのベテランで、最近昔の情熱に戻ってきて、このオブジェクト指向のイベント駆動型の明るい新しい世界に適応するのに苦労しています.シンプルさと再利用性の面で。私が取り組んできた簡単な例は、写真 (javascript、HTML、phonegap などでプログラムされた携帯電話) を撮り、サイズを変更して Web サイトにアップロードすることでした。理想的なシーケンスは次のとおりです。

  1. 写真を撮る
  2. 写真を img 要素に読み込む
  3. 画像のサイズを変更する (Pixastic を使用)
  4. Web サイトにアップロードする
  5. 成功の失敗をユーザーに通知する

各ステップが終了したときに次のステップに制御を戻す場合、これはすべて非常に単純な順次プログラムになりますが、実際には次のようになります。

  1. 写真を撮るのは非同期であるため、プログラムは画像が存在する前に img 要素に読み込もうとします。
  2. 写真の読み込みは非同期であるため、画像が完全に読み込まれる前に画像のサイズ変更が開始されます
  3. サイズ変更は非同期なので、画像のサイズが完全に変更される前に Web サイトへのアップロードが開始されます
  4. Web サイトへのアップロードは非同期であるため、写真が完全にアップロードされる前にプログラムが続行されます。

ところで、5 つのステップのうち 4 つには、コールバック関数が含まれます。

したがって、私の解決策は、前のステップの各ステップをネストし、.onload および他の同様の戦略を使用することです。次のようになります。

takeAPhoto(takeaphotocallback(photo) {
  photo.onload = function () {
    resizePhoto(photo, resizePhotoCallback(photo) {
      uploadPhoto(photo, uploadPhotoCallback(status) {
        informUserOnOutcome();
      });
    }); 
  };
  loadPhoto(photo);
});

(コードを本質的なものにするためにあまり多くの間違いを犯さなかったことを願っていますが、本物はあまりにも気が散っています)

これは、非同期が良くなく、同期が良いという完璧な例だと思います.UIイベント処理とは異なり、次のステップが実行される前に各ステップを終了する必要がありますが、コードはロシア人形の構造であり、混乱して読みにくい.コードの再利用性を達成するのは困難です。すべてのネストが原因で、必要なすべてのパラメーターを内部関数に持ち込むのは単純に困難であり、各コンテナーに順番に渡すか、悪意のあるグローバル変数を使用する必要があります。このコードで戻りコードが得られますが、最初のコンテナーは戻りコードが使用可能になるかなり前に終了します。

トムの最初の質問に戻ると、15 年前の非常に単純なプログラム (たとえば C 言語と馬鹿げた電子ボード) に対する、賢く、読みやすく、再利用しやすいソリューションは何でしょうか?

実際、要件は非常に単純であるため、Javascript と最新のプログラミングの基本的な理解が欠けているように感じます。確かに、テクノロジーは生産性を向上させるためのものですよね?.

お待ち頂きまして、ありがとうございます

恐竜のレイモンド ;-)

于 2010-10-22T04:37:34.607 に答える
1

コールバックの方法を試しましたが、これを機能させることができませんでした。理解する必要があるのは、実行が行われていなくても、値はまだアトミックであるということです。例えば:

alert('1');<---これら2つの機能は同時に実行されます

alert('2');<---これら2つの機能は同時に実行されます

しかし、このようにすると、実行の順序を知る必要があります。

loop=2;
total=0;
for(i=0;i<loop;i++) {
           total+=1;
           if(total == loop)
                      alert('2');
           else
                      alert('1');
}
于 2011-05-21T23:03:03.180 に答える
1

あなたの例では、最初の関数は、2 番目の関数が開始される前に実際に完了します。setTimeout は、タイムアウトに達するまで関数の実行を保持しません。単にバックグラウンドでタイマーを開始し、指定された時間の後にアラート ステートメントを実行します。

JavaScript で「スリープ」を行うネイティブな方法はありません。時間をチェックするループを作成することもできますが、それはクライアントに大きな負担をかけます。emacsian が説明したように、同期 AJAX 呼び出しを実行することもできますが、サーバーに余分な負荷がかかります。setTimeout がどのように機能するかを理解すれば、ほとんどの場合、これは十分に単純なはずです。

于 2009-12-07T10:50:38.033 に答える
1

JavaScript では、コードを待機させる方法はありません。私はこの問題を抱えていましたが、サーバーへの同期SJAX呼び出しを行う方法でした。サーバーは実際にスリープを実行するか、戻る前に何らかのアクティビティを実行し、jsは待機します。

同期 AJAX の例: http://www.hunlock.com/blogs/Snippets:_Synchronous_AJAX

于 2009-12-07T10:42:38.050 に答える
1

純粋な Javascript を使用することに固執しない場合は、Livescriptでシーケンシャル コードを作成できます次の例をご覧ください。

# application
do
    i = 3
    console.log td!, "start"
    <- :lo(op) ->
        console.log td!, "hi #{i}"
        i--
        <- wait-for \something
        if i is 0
            return op! # break
        lo(op)
    <- sleep 1500ms
    <- :lo(op) ->
        console.log td!, "hello #{i}"
        i++
        if i is 3
            return op! # break
        <- sleep 1000ms
        lo(op)
    <- sleep 0
    console.log td!, "heyy"

do
    a = 8
    <- :lo(op) ->
        console.log td!, "this runs in parallel!", a
        a--
        go \something
        if a is 0
            return op! # break
        <- sleep 500ms
        lo(op)

出力:

0ms : start
2ms : hi 3
3ms : this runs in parallel! 8
3ms : hi 2
505ms : this runs in parallel! 7
505ms : hi 1
1007ms : this runs in parallel! 6
1508ms : this runs in parallel! 5
2009ms : this runs in parallel! 4
2509ms : hello 0
2509ms : this runs in parallel! 3
3010ms : this runs in parallel! 2
3509ms : hello 1
3510ms : this runs in parallel! 1
4511ms : hello 2
4511ms : heyy
于 2016-04-17T04:32:44.807 に答える
0

これを調べるもう 1 つの方法は、ある機能から別の機能にデイジー チェーン接続することです。呼び出されたすべての関数に対してグローバルな関数の配列を用意します。たとえば、次のようにします。

arrf: [ f_final
       ,f
       ,another_f
       ,f_again ],

次に、実行したい特定の「f」に整数の配列を設定します。

var runorder = [1,3,2,0];

次に、「runorder」をパラメーターとして使用して初期関数を呼び出します。たとえば、f_start(runorder);

次に、各関数の最後で、インデックスを次の「f」にポップして runorder 配列を実行し、それを実行します。「runorder」をパラメーターとして渡しますが、配列は 1 減らします。

var nextf = runorder.shift();
arrf[nextf].call(runorder);

明らかに、これは、別の関数に連鎖しないインデックス 0 などの関数で終了します。これは完全に決定論的であり、「タイマー」を回避します。

于 2016-08-13T13:38:59.337 に答える
0

コードを string、iterate、eval、setTimeout、および recursion に入れて、残りの行を続行します。間違いなくこれを改善するか、的を射ていない場合は捨てます。私の意図は、本当に、本当に基本的なユーザー テストをシミュレートするために使用することです。

再帰と setTimeout により、シーケンシャルになります。

考え?

var line_pos = 0;
var string =`
    console.log('123');
    console.log('line pos is '+ line_pos);
SLEEP
    console.log('waited');
    console.log('line pos is '+ line_pos);
SLEEP
SLEEP
    console.log('Did i finish?');
`;

var lines = string.split("\n");
var r = function(line_pos){
    for (i = p; i < lines.length; i++) { 
        if(lines[i] == 'SLEEP'){
            setTimeout(function(){r(line_pos+1)},1500);
            return;
        }
        eval (lines[line_pos]);
    }
    console.log('COMPLETED READING LINES');
    return;
}
console.log('STARTED READING LINES');
r.call(this,line_pos);

出力

STARTED READING LINES
123
124
1 p is 0
undefined
waited
p is 5
125
Did i finish?
COMPLETED READING LINES
于 2018-05-10T05:55:47.207 に答える