ホームページ > 記事 > ウェブフロントエンド > JS関数のsetTimeoutの詳細な紹介
この記事は主にsetTimeoutからのjs関数の実行処理を紹介していますので、必要な方は参考にしてください
正直、この記事を書いた時は叩かれて少し落ち込んでいました。私はちょっといじるのが好きなので、偶然この「シンプルな」機能を目にしました:
for (var i = 0; i < 5; i++) { setTimeout(function () { console.log(i) }, i * 1000); } console.log(i);
え?これは昔見た、「5」を印刷し、次に「5」を印刷し、5 が 6 枚印刷されるまで毎秒 5 を印刷するという実装方法ではないでしょうか。ここで疑問が生じます。0、1、2、3、4、5 を順番に出力したい場合はどうすればよいでしょうか。実際、これまでに 2 つの方法があることはわかっていました。1 つは次のようなものです:
function log(i){ setTimeout(function(){ console.log(i) },i*1000) }; for (var i = 0; i < 5; i++) { log(i) ; } console.log(i);
もう一つはこれです:
for(var i=0;i<5;i++){ (function(e){ setTimeout(function(){ console.log(e) },i*1000); })(i); }; console.log(i);
冗談を恐れないでください。これまでは、これら 2 つの関数が実際に何に使われているか理解していませんでした。ただ無理やり覚えてこのように修正しましたが、実際にはそうではありません。私は強迫性障害を患っています。そこで、ゆっくり分析してみたところ、上記のコードは、条件が満たされたとき、条件が満たされたとき、
setTimeout(function(){ console.log(i) },0*1000);
i=2 のときに分けられることがわかりました。 ; 条件が満たされている場合 ;
setTimeout(function(){ console.log(i) },1*1000);
i=3 の場合は条件が満たされている;
setTimeout(function(){ console.log(i) },2*1000);
i=5 の場合は条件が満たされていない場合ループし、 for ループの後に console.log(i) を実行し、最後に 5 を毎秒出力します
非常に興味深いのですが、なぜ setTimeout 内の console.log が for ループの外側の console.log の後に実行されるのでしょうか。 => "キュー" という言葉に気づくまでは、キューはマクロタスクキュー (Macro Task) とマイクロタスクキュー (Micro Task) に分かれていました。 JavaScript では、
macro-task には script (コード全体) 、 setTimeout 、 setInterval が含まれます。 、setImmediate、I/O、UI レンダリング。
マイクロタスクには、process.nextTick、Promises、Object.observe、MutationObserverが含まれます
上記関数のsetTimeoutはマクロタスクです
jsでは、イベントループの順序はスクリプトから始まる最初のループです。次にグローバルコンテキスト 関数呼び出しスタックに入り、マクロタスクに遭遇した場合、それを処理するモジュールに渡します。マイクロタスクに遭遇した場合、コールバック関数をマクロタスクキューに入れます。コールバック関数をキュー内のマイクロタスクに入れます。関数呼び出しスタックがクリアされ、グローバル実行コンテキストのみが残るまで、すべてのマイクロタスクが実行され始めます。 すべての実行可能なマイクロタスクが実行された後。ループはマクロタスク内のタスクキューを再度実行し、実行後にすべてのマイクロタスクを実行し、このようにループが続きます。
これが、setTimeout 内の console.log が for ループの外側の console.log の後に実行される理由です。関数実行コンテキストでは、seiTimeout 関数はマクロタスクを処理するためにキューに配置されるため、ループはsetTimeout 内の関数は実行されませんが、キュー内の関数が実行される前にコード全体 (キュー以外) が実行されるまで待機します。これを書くのは少し混乱するかもしれません。実際、私も少し混乱しています。ははは! !
理解を深めるために、Promise を追加してみることもできます。
setTimeout(function(){ console.log(i) },3*1000);
説明します =>
1 まず、スクリプト タスク ソースが最初に実行され、グローバル コンテキストがプッシュされます。スタックに。
2. スクリプト タスクのソース コードが実行中に setTimeout に遭遇すると、マクロタスクとして、そのコールバック関数が独自のキューに入れられます。
3. スクリプトタスクソースのコードは、実行中に Promise インスタンスに遭遇します。 Promise コンストラクターの最初のパラメーターは、現在のタスクが直接実行される場合はキューに入れられないため、この時点では 1 が出力されます。
4. forループ内でresolve関数に遭遇すると、関数はスタックにプッシュされてからポップアウトされます。このとき、PromiseのステータスはFulfilledになります。次に、コードが実行され、console.log(2) が検出され、2 が出力されます。
5. 次に実行すると、コードは then メソッドに遭遇し、そのコールバック関数がマイクロタスクとしてスタックにプッシュされ、Promise のタスクキューに入ります。このとき、Promise の then の関数コールバック関数も同様です。つまり、関数コンテキスト、つまりスクリプト内のすべての非キュー コードが実行され、マイクロタスク キューが処理されるまで、それらはそれぞれのタスク キューに配置されます。マクロタスク キューの前に、
全体的な順序は次のとおりです: コンテキスト非キュー コード > マイクロタスク キュー コールバック関数コード > マクロタスク キュー コールバック関数コード
6 その後、コードが実行され、console.log(3) が次のようになります。このとき検出されたため、3 が出力されます。
7. 3 を出力した後、最初のマクロタスク スクリプトのコードが実行され、この時点でキュー内のすべてのマイクロタスクの実行が開始されます。 then のコールバック関数はスタックにプッシュされ、その後ポップアウトされます。この時点で、すべてのマイクロタスクが完了し、最初のサイクルが終了します。 2回目のループはsetTimeoutのタスクキューから始まり、setTimeoutのコールバック関数がスタックにプッシュされてからポップアウトされます。このとき、4が出力されます。
最後に、理解を深めるために、別のコードを示します:
setTimeout(function(){ console.log(i) },4*1000);
実行結果が次の場合: golb1=>glob1_promise=>glob1_then=>timeout1=>timeout1_promise=>timeout1_then=> prp_timeout=> ;time_timeout=>timeout1_timeout1,
非同期キューは入門編かもしれません! ~~上記のコードは少し乱雑に見えますが、asyns を使用してそれを変換する方が良いかもしれませんが、これは多かれ少なかれ setTimeout から得た洞察です
上記は私が皆さんのためにコンパイルしたものです。将来的にはもっと良くなりますように みんなが助けてくれます。
関連記事:
Three.jsを使用したWeChatジャンプゲームの実装方法
以上がJS関数のsetTimeoutの詳細な紹介の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。