JS for ループで setTimeout を使用する 4 つのソリューション

JS for ループで setTimeout を使用する 4 つのソリューション

概要

まず、setTimeout 遅延の動作メカニズムを簡単に見てみましょう。 setTimeout は、まずコールバック関数を待機キューに配置し、待機領域にある他のメイン プログラムが実行された後、コールバック関数を時系列順に実行します。それは本質的には範囲の問題です。

したがって、これを実行すると、目的の出力 1.2.3.4.5 は得られず、5 つの連続した 6 が出力されます。

(var i=1; i<=5; i++) の場合 {
    setTimeout(関数タイマー() {
        コンソールにログ出力します。
     }, i*1000 );
}

これは、setTimeout が非同期で実行されるためです。for ループが実行されるたびに、setTimeout は 1 回実行されますが、内部の関数は実行されません。代わりに、タスク キューに配置され、実行を待機します。メインライン上のタスクが完了した場合にのみ、タスクキュー内のタスクが実行されます。つまり、 for ループが完全に終了するまで待機してから fun 関数を実行します。ただし、 for ループが終了すると、 i の値は 6 になっています。そのため、タイマーは 5 秒間実行されますが、コンソールの内容は 6 のままです。

(注: for ループは、開始から終了まで数マイクロ秒または数ミリ秒続く必要があります。タイマーが 1 秒経過すると、for ループはすでに完了しています。)

別のケースを見てみましょう。

(var i=1; i<=5; i++) の場合 {
    (関数() {
        setTimeout(関数タイマー() {
            コンソールにログ出力します。
        }, i*1000 );
    })();
}

setTimeout の動作メカニズムから、すべての外部メイン プログラムが最初に実行されることがわかります。for ループではクロージャが形成されますが、fun は実際のパラメーターを見つけないため、最初の例と実際の違いはなく、5 つの連続した 6 が引き続き出力されます。

解決策 1: クロージャ

クロージャを使用するのは古典的なアプローチです。

(var i=1; i<=5; i++) の場合 {
    (関数(j) {
        setTimeout(関数タイマー() {
            コンソールログ(j);
        }, j*1000 );
    })(私);
}

予想される結果は、1 から 5 までの順番の出力と一致していることがわかります。これは、実際のパラメータがタイマー内の i に強く依存しているためです。

クロージャを通して、変数 i がメモリ上に常駐します。j が出力される際、外部関数の変数値 i が参照されます。i の値はループに基づいており、setTimeout が実行されると内部の出力が決定されます。

解決策2: 構造を分割する

setTimeout の定義と呼び出しを別の部分に分けることもできます。

関数タイマー(i) {
    タイムアウトを設定します( console.log( i ), i*1000 );
}
(var i=1; i<=5; i++) の場合 {
    タイマー(i);
}

コンソールの出力は、引き続き 1 から 5 の順になっています。

解決策3:

es6 の let を使用してこの問題を解決する別の方法を次に示します。

(i=1; i<=5; i++) の場合 {
    setTimeout(関数タイマー() {
        コンソールにログ出力します。
     }, i*1000 );
}

最初の例と比較すると、この例では var が let に変更されるだけですが、コンソールには 1 から 5 が順番に出力されます。

for ループの先頭にある let は i を for ループにバインドするだけでなく、実際にループ本体の各反復に再バインドし、前の反復の終了時の値が再割り当てされるようにします。 setTimeout の function() は新しいスコープに属します。var で定義された変数は、この関数の実行スコープに渡すことはできません。let を使用してブロック変数を宣言すると、このブロックで動作できるため、function は変数 i を使用できます。この匿名関数のパラメーター スコープは for パラメーターのスコープとは異なりますが、これは this を利用して実現されています。この匿名関数のスコープはクラスの属性に多少似ており、内部メソッドで使用できます。

解決策4: setTimeoutの3番目のパラメータ

(i=1; i<=5; i++) の場合 {
    setTimeout(関数タイマー() {
        コンソールにログ出力します。
     }, i*1000, i );
}

毎回渡されるパラメータはforループから取得した値なので、1~5が順番に出力されます。

上記は、JS の for ループで setTimeout を使用するための 4 つのソリューションの詳細です。JS で setTimeout を使用する方法の詳細については、123WORDPRESS.COM の他の関連記事に注目してください。

以下もご興味があるかもしれません:
  • JavaScript は setTimeout を使用してカウントダウン効果を実現します
  • JavaScript setTimeout()の基本的な使い方は何ですか?
  • JavaScript setInterval() と setTimeout() タイマー
  • settimeoutを使用するだけで、JavaScriptの動作メカニズムを確認できます。
  • setTimeout を通して JS の動作メカニズムを理解する方法
  • setTimeoutからのjs関数実行プロセスを見てみましょう
  • js setTimeout を使用してラウンドロビンアニメーションを実装する方法を学ぶ
  • JavaScript タイマーの使用状況の分析 [setTimeout と clearTimeout]
  • JS のタイマー setInterval と setTImeout の this ポイント問題の詳細な説明
  • JavaScript の setTimeout について

<<:  nginxでの共有メモリの使用に関する詳細な説明

>>:  Docker での RocketMQ の詳細なインストールと使用

推薦する

Web 上の要素を非表示にする方法とその利点と欠点

ソースコードの例: https://codepen.io/shadeed/pen/03caf6b36...

jsBridgeの動作メカニズムを1つの記事で学ぶ

目次js 呼び出しメソッドアンドロイド1.jsはネイティブを呼び出す2. ネイティブコールjs iO...

MySQLの整数データ型tinyintの詳細な説明

目次1.1Tinyint型の説明1.2 練習環境の説明1.3 未署名属性の追加1.3.1 SQLモー...

MySQL サービスとデータベース管理

目次1. サービスの開始と停止の手順1.1 Windows での MySQL 5.7 の公式 MSI...

単一テーブルのMySQLバックアップとリストアに関する簡単な説明

A. MySQLバックアップツールxtrabackupのインストール1. Percona 公式 xt...

MySql の忘れたパスワードの変更方法はバージョン 5.7 以上に適しています

1. まずmysqld.exeプロセスを停止します2. cmd を開き、mysql の bin ディ...

MySQLの一般クエリログとスロークエリログの分析

MySQL のログには、エラー ログ、バイナリ ログ、一般クエリ ログ、スロー クエリ ログなどが含...

Idea で Docker を使用して SpringBoot プロジェクトをデプロイする詳細な手順

序文プロジェクト要件: Dockeridea に Docker プラグインをインストールし、Dock...

MySQLでテーブル名を変更する方法と注意すべき点

目次1. テーブル名を変更する方法2. 注記要約: 1. テーブル名を変更する方法RENAME TA...

JS でカルーセル画像を実装するいくつかの方法

カルーセル主なアイデアは次のとおりです。大きなコンテナには、コンテナの幅の整数倍の非常に長いテーブル...

vue 動的コンポーネント

目次1. コンポーネント2. キープアライブ2.1 問題点2.2 キープアライブを使って解決する2....

CentOS で yum を使用して rabbitmq-server をインストールする方法

RabbitMQをインストールする前にSocatをインストールする必要があります。そうしないと、Ra...

あるテーブルからバッチデータをクエリし、それを別のテーブルに挿入する MySQL の完全な例

事前に言っておくNodejs はデータベースを非同期操作として読み取るため、データベースがデータを読...

知らないかもしれない実用的なTypeScriptのヒント

目次序文関数のオーバーロードマッピングタイプ部分的、読み取り専用、Null 可能、必須選択、記録除外...

DOCTYPE 文書型宣言 (Web ページ愛好家必読)

DOCTYPE 宣言 作成するすべてのページの先頭に、ドキュメント宣言が必要です。はい、そうでしょう...