JavaScriptシングルスレッド
JavaScriptの単一スレッドは、その目的に関連しています。ブラウザのスクリプト言語として、JavaScriptの主な目的は、ユーザーと対話してDOMを操作することです。これにより、単一のスレッドのみができると判断され、それ以外の場合は非常に複雑な同期の問題を引き起こします。たとえば、JavaScriptが同時に2つのスレッドがあると仮定します。1つのスレッドは特定のDOMノードにコンテンツを追加し、もう1つのスレッドはこのノードを削除します。したがって、複雑さを避けるために、JavaScriptはその出生からの単一のスレッドであり、この言語の中核的な特徴となり、将来は変わりません。
キュータスク
単一のスレッドは、すべてのタスクをキューに掲載する必要があり、次のタスクが実行される前に以前のタスクが実行されることを意味します。前のタスクに長い時間がかかる場合、次のタスクが待たなければなりません。
非同期イベントドライバー
ブラウザの多くの動作は、マウスクリックイベント、ウィンドウサイズのドラッグイベント、タイマートリガーイベント、XMLHTTPREQUEST COLLBACKなど:非同期イベントが発生するとイベントキューに入ります。ブラウザには、内部の大きなメッセージループ、イベントループがあり、大規模なイベントキューとプロセスイベントを投票します。たとえば、ブラウザは現在、オンクリックイベントの処理に忙しく、次に別のイベントが発生し(ウィンドウオンサイズなど)、この非同期イベントがイベントキューに入れられ、処理を待ちます。このイベントは、以前の処理が完了し、無料の場合にのみ実行されます。
イベントループ
JavaScriptはシングルスレッドですが、ブラウザはシングルスレッドではありません
ブラウザには、少なくとも次のプロセスがあります
1。ブラウザGUIレンダリングスレッド
2。JavaScriptエンジンスレッド
3。ブラウザの時刻トリガースレッド
4.ブラウザイベントはスレッドをトリガーします
5。ブラウザHTTP非同期リクエストスレッド
JavaScriptエンジンはシングルスレッドであるため、コードは最初にキューに押し付けられ、次にエンジンがファーストアウトで実行されます。イベント処理機能とタイマー実行機能もこのキューに配置され、無限のループを使用して、チームのヘッドから機能を継続的に抽出して実行します。これはイベントループです。
要約すると、JSはシングルスレッドですが、ブラウザはマルチスレッドです。非同期に遭遇すると、ブラウザはイベントループに非同期コールバックを配置します。 JSスレッドがビジーでない場合は、イベントループをお読みください。
タイマーの原則
タイマーの使用方法
setimeout(fn、delay)
setinterval(fn、delay)
fnは関数または文字列であり、遅延は遅延の時間、ユニットはミリ秒です
注意すべきことがあります
1. FNは文字列になる可能性がありますが、このように使用することは決して推奨されません。
2。FNにこの関数がある場合、これは実行時にウィンドウを指します。
JSシングルスレッドとイベントループをよく理解すれば、タイマーの原則は理解しやすくなります。
タイマーが設定されている場合、遅延時間に達すると、ブラウザは遅延実行イベントをイベントループに入れます。時間が経過すると、JSスレッドがアイドル状態の場合、実行されます(そのため、タイマーの精度は不正確です)
私は常に機能を投票するSettimeOutとSetIntervalの違いについての記事を読みました。コードは次のとおりです
コードコピーは次のとおりです。
setimeout(function(){
setimeout(arguments.callee、100)
}、100)
setInterval(function(){}、1000)
記事の一般的な意味は、Callback関数が実行された後、SettimeOutが次のタイマーを開始するため、間隔で実行する必要があり、Setintervalは常に実行されます。実行を続けるJSスレッドに遭遇した場合、イベントループに複数のコールバックを追加できます。 JSスレッドがビジーでない場合、複数の実行が次々に実行されます。
テスト後、IE、FF、Chrome、Opera、およびSafariの下で、Setintervalは特定の間隔にあることがわかりました。
テストコードは次のとおりです
コードコピーは次のとおりです。
setInterval(function(){
xx.innerhtml = xx.innerhtml+1;
}、100);
for(var i = 0; i <6000000; i ++){
xx.offsetwidth
}
setimeout(function(){
デバッガ;
}、10)
ブレークポイントがまだ印刷されている場合は1だけです
タイマーの精度の問題
JSシングルスレッドのため、忙しさに遭遇した場合、タイマーは間違いなく不正確になり、間違いなく長くなります。これは解決できず、解決策はないようです。
別の精度の問題は、最小間隔のsettimeout(fun、0)です
JSスレッドがビジーでない場合、0秒後にすぐに実行することは不可能です。常に最小間隔があり、各ブラウザはまだ異なります。これはテストされていません。
W3Cの標準に関する記事を読みました。タイマーの最小時間実行は4msです。ソースを見つけることができない場合、ソースを確認する方法はありません! ! !
タイマーに関連するいくつかの最適化
タイマーを作成する際には、まだいくつかの最適化があります
1.たとえば、window.onresizeをバインドすると、ブラウザがズームされているときにトリガーが非常に頻繁に発生するため、実行を遅らせることができます。次の実行がクリアされると、頻繁に実行されます。
擬似コードは次のとおりです
コードコピーは次のとおりです。
varタイマー;
関数r(){
ClearTimeout(タイマー);
Timer = setimeout(function(){
//何かをします
}、150);
}
2。スクロールバーが引き下げられると、少しです。たとえば、画像のレイジーロードには、過度の計算を避けるためのタイマーも必要です。
3.タイマーが必要な場所が複数ある場合、それらをタイマーに統合できます。時間間隔は最小のものです。次に、実行する必要があるコールバック関数が配列に詰め込まれます。時間間隔に達したら、アレイを繰り返して実行します。
小さなデモ
コードコピーは次のとおりです。
<!doctype html>
<html>
<head>
<Meta charset = "utf-8" />
<style>
.wrap {width:80%;マージン:30px Auto;ボーダー:1pxソリッド#ccc;パディング:20px;}
.c {border:1px solid #ccc;高さ:30px;マージンボトム:20px;}
</style>
</head>
<body>
<div id = "xx"> </div>
<div>
<div id = "a1"> 0 </div>
<div id = "a2"> 0 </div>
<div id = "a3"> 0 </div>
<div id = "a4"> 0 </div>
</div>
<スクリプトsrc = "http://static.paipaiimg.com/paipai_h5/js/ttj/zepto.min.js"> </script>
<script type = "text/javascript">
var runtime = {
オプション:{
ステップ:1000
}、
コールバック:[]、
addcallbacks:[]、
開始:FALSE、
タイマー:ヌル、
拡張:function(){
var target = arguments [0] || {}、i = 1、length = arguments.length、options;
if(typeof target!= "object" && typeof target!= "function"))
ターゲット= {};
for(; i <length; i ++)
if((options = arguments [i])!= null)
for(optionsのvar名){
var copy = options [name];
if(ターゲット===コピー)
続く;
if(copy!== undefined)
ターゲット[name] = copy;
}
ターゲットを返します。
}、
init:function(options){
$ .extend(this、this.options、options || {});
}、
追加:function(fun、options){
options = options || {};
this.addcallbacks.push({
楽しい:楽しい、
starttime:new date()。gettime()、
ステップ:options.step || this.step、
I:1
});
var self = this;
if(!this.start){
this.callbacks = [fun];
this.start = true;
this.starttime = new date()。getTime();
this.timer = setInterval(function(){
self.done();
}、this.step);
}
}、
完了:function(){
var callbacks = this.callbacks、
自己=これ、
newarr = [];
$ .each(callbacks、function(i、obj){
if(obj.step == self.step){
obj.fun();
}それ以外{
if(obj.i == obj.step/self.step){
if((new date()。gettime()) - obj.starttime> obj.step*2/3){
obj.fun();
}
obj.i = 1;
}それ以外{
obj.i = obj.i + 1;
}
}
});
$ .each(this.addcallbacks、function(i、obj){
if(obj.step == self.step){
if((new date()。gettime()) - obj.starttime> obj.step*2/3){
obj.fun();
callbacks.push(obj);
}それ以外{
newarr.push(obj);
}
}それ以外{
obj.i = obj.i + 1;
callbacks.push(obj);
}
});
this.addcallbacks = newArr;
}、
clear:function(){
ClearInterval(this.timer);
}
}
runtime.init();
runtime.add(function(){
a1.innerhtml = ~~ a1.innerhtml+1;
});
runtime.add(function(){
a2.innerhtml = ~~ a2.innerhtml+1;
}、{ステップ:2000});
runtime.add(function(){
a3.innerhtml = ~~ a3.innerhtml+1;
}、{ステップ:4000});
runtime.add(function(){
a4.innerhtml = ~~ a4.innerhtml+1;
}、{ステップ:8000});
</script>
</body>
</html>
JavaScriptタイマーについて何か考えましたか?ご質問がある場合はメッセージを残してください。