成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

你應(yīng)該知道的 setTimeout 秘密

mrcode / 3476人閱讀

摘要:的一些秘密中回調(diào)函數(shù)的由于方法是瀏覽器對(duì)象提供的,因此第一個(gè)參數(shù)函數(shù)中的其實(shí)是指向?qū)ο?,這跟變量的作用域有關(guān)。原文鏈接你應(yīng)該知道的秘密如果你有疑問或建議,歡迎在下面的評(píng)論區(qū)評(píng)論

計(jì)時(shí)器setTimeout是我們經(jīng)常會(huì)用到的,它用于在指定的毫秒數(shù)后調(diào)用函數(shù)或計(jì)算表達(dá)式。

語法:setTimeout(code, millisec, args);

注意:如果code為字符串,相當(dāng)于執(zhí)行eval()方法來執(zhí)行code。

當(dāng)然,這一篇文章并不僅僅告訴你怎么用setTimeout,而且理解其是如何執(zhí)行的。

1、setTimeout原理

先來看一段代碼:

var start = new Date(); 
var end = 0; 
setTimeout(function() {  console.log(new Date() - start); }, 500); 
while (new Date() - start <= 1000) {}

在上面的代碼中,定義了一個(gè)setTimeout定時(shí)器,延時(shí)時(shí)間是500毫秒。

你是不是覺得打印結(jié)果是: 500

可事實(shí)卻是出乎你的意料,打印結(jié)果是這樣的(也許你打印出來會(huì)不一樣,但肯定會(huì)大于1000毫秒):

這是為毛呢?究其原因,這是因?yàn)?JavaScript是單線程執(zhí)行的。也就是說,在任何時(shí)間點(diǎn),有且只有一個(gè)線程在運(yùn)行JavaScript程序,無法同一時(shí)候運(yùn)行多段代碼。

再來看看瀏覽器下的JavaScript。

瀏覽器的內(nèi)核是多線程的,它們?cè)趦?nèi)核控制下相互配合以保持同步,一個(gè)瀏覽器至少實(shí)現(xiàn)三個(gè)常駐線程:JavaScript引擎線程,GUI渲染線程,瀏覽器事件觸發(fā)線程。

JavaScript引擎是基于事件驅(qū)動(dòng)單線程執(zhí)行的,JavaScript引擎一直等待著任務(wù)隊(duì)列中任務(wù)的到來,然后加以處理,瀏覽器無論什么時(shí)候都只有一個(gè)JavaScript線程在運(yùn)行JavaScript程序。

GUI渲染線程負(fù)責(zé)渲染瀏覽器界面,當(dāng)界面需要重繪(Repaint)或由于某種操作引發(fā)回流(Reflow)時(shí),該線程就會(huì)執(zhí)行。但需要注意,GUI渲染線程與JavaScript引擎是互斥的,當(dāng)JavaScript引擎執(zhí)行時(shí)GUI線程會(huì)被掛起,GUI更新會(huì)被保存在一個(gè)隊(duì)列中等到JavaScript引擎空閑時(shí)立即被執(zhí)行。

事件觸發(fā)線程,當(dāng)一個(gè)事件被觸發(fā)時(shí),該線程會(huì)把事件添加到待處理隊(duì)列的隊(duì)尾,等待JavaScript引擎的處理。這些事件可來自JavaScript引擎當(dāng)前執(zhí)行的代碼塊如setTimeout、也可來自瀏覽器內(nèi)核的其他線程如鼠標(biāo)點(diǎn)擊、Ajax異步請(qǐng)求等,但由于JavaScript的單線程關(guān)系,所有這些事件都得排隊(duì)等待JavaScript引擎處理(當(dāng)線程中沒有執(zhí)行任何同步代碼的前提下才會(huì)執(zhí)行異步代碼)。

到這里,我們?cè)賮砘仡櫼幌伦畛醯睦樱?/p>

var start = new Date();
 var end = 0;
 setTimeout(function() {  console.log(new Date() - start); }, 500);
 while (new Date() - start <= 1000) {}

雖然setTimeout的延時(shí)時(shí)間是500毫秒,可是由于while循環(huán)的存在,只有當(dāng)間隔時(shí)間大于1000毫秒時(shí),才會(huì)跳出while循環(huán),也就是說,在1000毫秒之前,while循環(huán)都在占據(jù)著JavaScript線程。也就是說,只有等待跳出while后,線程才會(huì)空閑下來,才會(huì)去執(zhí)行之前定義的setTimeout。

最后 ,我們可以總結(jié)出,setTimeout只能保證在指定的時(shí)間后將任務(wù)(需要執(zhí)行的函數(shù))插入任務(wù)隊(duì)列中等候,但是不保證這個(gè)任務(wù)在什么時(shí)候執(zhí)行。一旦執(zhí)行javascript的線程空閑出來,自行從隊(duì)列中取出任務(wù)然后執(zhí)行它。

因?yàn)閖avascript線程并沒有因?yàn)槭裁春臅r(shí)操作而阻塞,所以可以很快地取出排隊(duì)隊(duì)列中的任務(wù)然后執(zhí)行它,也是這種隊(duì)列機(jī)制,給我們制造一個(gè)異步執(zhí)行的假象。

2、setTimeout的好搭檔“0”

也許你見過下面這一段代碼:

setTimeout(function(){ // statement}, 0);

上面的代碼表示立即執(zhí)行。本意是立刻執(zhí)行調(diào)用函數(shù),但事實(shí)上,上面的代碼并不是立即執(zhí)行的,這是因?yàn)閟etTimeout有一個(gè)最小執(zhí)行時(shí)間,當(dāng)指定的時(shí)間小于該時(shí)間時(shí),瀏覽器會(huì)用最小允許的時(shí)間作為setTimeout的時(shí)間間隔,也就是說即使我們把setTimeout的延遲時(shí)間設(shè)置為0,被調(diào)用的程序也沒有馬上啟動(dòng)。

不同的瀏覽器實(shí)際情況不同,IE8和更早的IE的時(shí)間精確度是15.6ms。不過,隨著HTML5的出現(xiàn),在高級(jí)版本的瀏覽器(Chrome、ie9+等),定義的最小時(shí)間間隔是不得低于4毫秒,如果低于這個(gè)值,就會(huì)自動(dòng)增加,并且在2010年及之后發(fā)布的瀏覽器中采取一致。

所以說,當(dāng)我們寫為 setTimeout(fn,0) 的時(shí)候,實(shí)際是實(shí)現(xiàn)插隊(duì)操作,要求瀏覽器“盡可能快”的進(jìn)行回調(diào),但是實(shí)際能多快就完全取決于瀏覽器了。

setTimeout(fn, 0)有什么用處呢?其實(shí)用處就在于我們可以改變?nèi)蝿?wù)的執(zhí)行順序!因?yàn)闉g覽器會(huì)在執(zhí)行完當(dāng)前任務(wù)隊(duì)列中的任務(wù),再執(zhí)行setTimeout隊(duì)列中積累的的任務(wù)。

通過設(shè)置任務(wù)在延遲到0s后執(zhí)行,就能改變?nèi)蝿?wù)執(zhí)行的先后順序,延遲該任務(wù)發(fā)生,使之異步執(zhí)行。

來看一個(gè)網(wǎng)上很流行的例子:

document.querySelector("#one input").onkeydown = function() {  
     document.querySelector("#one span").innerHTML = this.value;
 }; 
document.querySelector("#second input").onkeydown = function() {    
     setTimeout(function() {  
         document.querySelector("#second span").innerHTML = document.querySelector("#second input").value; }, 0);
};

`實(shí)例:實(shí)例

當(dāng)你往兩個(gè)表單輸入內(nèi)容時(shí),你會(huì)發(fā)現(xiàn)未使用setTimeout函數(shù)的只會(huì)獲取到輸入前的內(nèi)容,而使用setTimeout函數(shù)的則會(huì)獲取到輸入的內(nèi)容。

這是為什么呢?

因?yàn)楫?dāng)按下按鍵的時(shí)候,JavaScript 引擎需要執(zhí)行 keydown 的事件處理程序,然后更新文本框的 value 值,這兩個(gè)任務(wù)也需要按順序來,事件處理程序執(zhí)行時(shí),更新 value值(是在keypress后)的任務(wù)則進(jìn)入隊(duì)列等待,所以我們?cè)?keydown 的事件處理程序里是無法得到更新后的value的,而利用 setTimeout(fn, 0),我們把取 value 的操作放入隊(duì)列,放在更新 value 值以后,這樣便可獲取出文本框的值。

未使用setTimeout函數(shù),執(zhí)行順序是:`onkeydown => onkeypress => onkeyup

使用setTimeout函數(shù),執(zhí)行順序是:onkeydown => onkeypress => function => onkeyup`

雖然我們可以使用keyup來替代keydown,不過有一些問題,那就是長(zhǎng)按時(shí),keyup并不會(huì)觸發(fā)。

長(zhǎng)按時(shí),keydown、keypress、keyup的調(diào)用順序:

keydown
keypress
keydown
keypress
...
keyup

也就是說keyup只會(huì)觸發(fā)一次,所以你無法用keyup來實(shí)時(shí)獲取值。

我們還可以用setImmediate()來替代setTimeout(fn,0)

if (!window.setImmediate) {  
    window.setImmediate = function(func, args){  
      return window.setTimeout(func, 0, args);  
   };  
  window.clearImmediate = window.clearTimeout;
 }

setImmediate()`方法用來把一些需要長(zhǎng)時(shí)間運(yùn)行的操作放在一個(gè)回調(diào)函數(shù)里,在瀏覽器完成后面的其他語句后,就立刻執(zhí)行這個(gè)回調(diào)函數(shù),必選的第一個(gè)參數(shù)func,表示將要執(zhí)行的回調(diào)函數(shù),它并不需要時(shí)間參數(shù)。

注意:目前只有IE10支持此方法,當(dāng)然,在Nodejs中也可以調(diào)用此方法。

3、setTimeout的一些秘密

3.1 setTimeout中回調(diào)函數(shù)的this

由于setTimeout() 方法是瀏覽器 window 對(duì)象提供的,因此第一個(gè)參數(shù)函數(shù)中的this其實(shí)是指向window對(duì)象,這跟變量的作用域有關(guān)。

看個(gè)例子:

var a = 1; 
var obj = {  
a: 2, 
 test: function() {  setTimeout(function(){  console.log(this.a);  }, 0);  
} 
}; 
obj.test(); // 1

不過我們可以通過使用bind()方法來改變setTimeout回調(diào)函數(shù)里的this

var a = 1; 
var obj = { 
 a: 2, 
 test: function() {  
setTimeout(function(){  
console.log(this.a);  
}.bind(this), 0);  
}
 }; 
obj.test(); // 2

相關(guān)文章:JS中的call、apply、bind方法

3.2 setTimeout不止兩個(gè)參數(shù)

我們都知道,setTimeout的第一個(gè)參數(shù)是要執(zhí)行的回調(diào)函數(shù),第二個(gè)參數(shù)是延遲時(shí)間(如果省略,會(huì)由瀏覽器自動(dòng)設(shè)置。在IE,F(xiàn)ireFox中,第一次配可能給個(gè)很大的數(shù)字,100ms上下,往后會(huì)縮小到最小時(shí)間間隔,Safari,chrome,opera則多為10ms上下。)

其實(shí),setTimeout可以傳入第三個(gè)參數(shù)、第四個(gè)參數(shù)....,它們表示神馬呢?其實(shí)是用來表示第一個(gè)參數(shù)(回調(diào)函數(shù))傳入的參數(shù)。

setTimeout(function(a, b){  
console.log(a); // 3 
console.log(b); // 4},0, 3, 4);

原文鏈接:你應(yīng)該知道的 setTimeout 秘密

如果你有疑問或建議,歡迎在下面的評(píng)論區(qū)評(píng)論!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/50354.html

相關(guān)文章

  • 應(yīng)該知道 setTimeout 秘密

    摘要:的一些秘密中回調(diào)函數(shù)的由于方法是瀏覽器對(duì)象提供的,因此第一個(gè)參數(shù)函數(shù)中的其實(shí)是指向?qū)ο?,這跟變量的作用域有關(guān)。原文鏈接你應(yīng)該知道的秘密如果你有疑問或建議,歡迎在下面的評(píng)論區(qū)評(píng)論 計(jì)時(shí)器setTimeout是我們經(jīng)常會(huì)用到的,它用于在指定的毫秒數(shù)后調(diào)用函數(shù)或計(jì)算表達(dá)式。 語法:setTimeout(code, millisec, args); 注意:如果code為字符串,相當(dāng)于執(zhí)行eva...

    李世贊 評(píng)論0 收藏0
  • rem : web app適配秘密武器

    摘要:有與兩種方式來調(diào)整元素大小的值。如果你的頁面還需要適配到端,那么就老老實(shí)實(shí)的使用吧。在上面的實(shí)現(xiàn)中,我通過判斷設(shè)定了字體大小的范圍來避免上顯示過于夸張。二有的同學(xué)可能對(duì)的適配有點(diǎn)誤解。 最近看到這樣一個(gè)提問:我有一個(gè)750 x 1500尺寸的設(shè)計(jì)稿,設(shè)計(jì)稿上有一個(gè)150 x 50的按鈕,那么在寫頁面布局的時(shí)候,應(yīng)該如何確定按鈕的尺寸呢?。大多數(shù)同學(xué)在回答的時(shí)候提到了rem。但我發(fā)現(xiàn)很多...

    since1986 評(píng)論0 收藏0
  • rem : web app適配秘密武器

    摘要:有與兩種方式來調(diào)整元素大小的值。如果你的頁面還需要適配到端,那么就老老實(shí)實(shí)的使用吧。在上面的實(shí)現(xiàn)中,我通過判斷設(shè)定了字體大小的范圍來避免上顯示過于夸張。二有的同學(xué)可能對(duì)的適配有點(diǎn)誤解。 最近看到這樣一個(gè)提問:我有一個(gè)750 x 1500尺寸的設(shè)計(jì)稿,設(shè)計(jì)稿上有一個(gè)150 x 50的按鈕,那么在寫頁面布局的時(shí)候,應(yīng)該如何確定按鈕的尺寸呢?。大多數(shù)同學(xué)在回答的時(shí)候提到了rem。但我發(fā)現(xiàn)很多...

    MageekChiu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<