setTimeout()

基本使用

setTimeout( function|string, number );

setTimeout 方法接收兩個(gè)參數(shù)泞歉,第一個(gè)參數(shù)為回調(diào)函數(shù)函數(shù)或字符串,第二個(gè)參數(shù)為觸發(fā)時(shí)間(單位:毫秒)

setTimeout( function() {
    console.log('console after 1 second');
}, 1000 );
// console after 1 second

上面這段代碼將會(huì)在 1 秒后在控制臺(tái)打印出 console after 1 second

setTimeout( 
    'console.log("console after 2 seconds")',
    2000 
);
// console after 2 seconds

setTimeout的方式(注冊(cè)事件):有兩個(gè)參數(shù)映胁,第一個(gè)參數(shù)是函數(shù)阅悍,第二參數(shù)是時(shí)間值附鸽。調(diào)用setTimeout時(shí),把函數(shù)參數(shù)净宵,放到事件隊(duì)列中敲才。等主程序運(yùn)行完裹纳,再調(diào)用。
當(dāng)?shù)谝粋€(gè)參數(shù)為字符串紧武,而不是函數(shù)時(shí)會(huì)怎樣呢剃氧?setTimeout 方法會(huì)將這個(gè)字符串解析為一段 js 代碼,然后在 2 秒后執(zhí)行這段代碼阻星。如果這個(gè)字符串無法被解析為 js 代碼朋鞍,將會(huì)報(bào)錯(cuò)

setTimeout 的返回值
var timeout = setTimeout(function() {
    console.log('this is a timeout')
}, 1000);

console.log(timeout, typeof timeout);

// 1, "number"
// this is a timeout

用變量 timeout 接收 setTimeout() 的返回值,然后將 timeout 打印出來妥箕,會(huì)發(fā)現(xiàn) timeout 的值是 1滥酥,類型是number
為什么 setTimeout() 的返回值會(huì)是一個(gè)數(shù)值類型呢?是不是每一個(gè) setTimeout() 的返回值都會(huì)是1畦幢?

var timeout1 = setTimeout(function() {
    //
}, 1000);

var timeout2 = setTimeout(function() {
    //
}, 1000);

var timeout3 = setTimeout(function() {
    //
}, 1000);

console.log('timeout1---', timeout1);
console.log('timeout2---', timeout2);
console.log('timeout3---', timeout3);

// timeout1--- 1
// timeout2--- 2
// timeout3--- 3

從上面的代碼中能夠發(fā)現(xiàn)坎吻,每一個(gè) setTimeout()的返回值都不同,返回值并不都是1宇葱,而是都對(duì)應(yīng)著唯一的一個(gè)值
這個(gè)值其實(shí)就是對(duì)應(yīng)的setTimtout()的 ID瘦真,隨著當(dāng)前頁面定時(shí)器的不斷增多,當(dāng)需要對(duì)某一個(gè)定時(shí)器做操作時(shí)黍瞧,通過 ID 就能夠確定到該定時(shí)器
如何結(jié)束/阻止一個(gè) setTimeout 的執(zhí)行
實(shí)際項(xiàng)目中诸尽,添加一個(gè)定時(shí)器以后,在其回調(diào)函數(shù)還未執(zhí)行之前印颤,滿足某些條件時(shí)可能需要阻止該回調(diào)的執(zhí)行您机,也就是取消一個(gè)定時(shí)器,那這時(shí)候該怎么做呢年局?javascript 已經(jīng)為我們提供了現(xiàn)成的方法:

clearTimeout( timeout );

上面這個(gè)方法就可以阻止一個(gè)定時(shí)器的執(zhí)行际看,它接收一個(gè)參數(shù),這個(gè)參數(shù)就是需要取消的定時(shí)器的 ID某宪,也就是該定時(shí)器的返回值

var timeout = setTimeout(function() {
    alert('this is a timeout')
}, 1000);

clearTimeout( timeout );

上面代碼中的定時(shí)器timeout在一秒后并不會(huì)執(zhí)行仿村,因?yàn)橐呀?jīng)通過clearTimeout( timeout )取消了它的執(zhí)行
因?yàn)閠imeout的值是1锐朴,所以clearTimeout( 1 )也能夠取消這個(gè)定時(shí)器的執(zhí)行
實(shí)現(xiàn)異步編程
在之前的文章中已經(jīng)講過異步編程的概念兴喂,我們使用異步編程很重要的一個(gè)目的就是為了不因?yàn)楹臅r(shí)任務(wù)而阻塞其他 js 代碼的執(zhí)行
我們知道alert會(huì)阻塞 js 代碼的執(zhí)行,這是因?yàn)?js 是單線程的焚志,彈出框出現(xiàn)后如果不對(duì)其進(jìn)行操作就無法執(zhí)行后面的代碼(類似的confirm也是)

alert('this is an alert box');
var test = 'this is a text string';
console.log(test);

上面的代碼在彈出框出現(xiàn)后如果不點(diǎn)擊確定衣迷,將永遠(yuǎn)不會(huì)執(zhí)行后面的代碼

setTimeout(function() {
    alert('this is an alert box');
}, 1000);
var test = 'this is a text string';
console.log(test);

// this is a text string

上面的代碼將alert放在了一個(gè)延時(shí) 1 秒的定時(shí)器中,這樣就會(huì)先打印出test酱酬,過一秒后再顯示彈出框
或許你會(huì)說壶谒,本身alert就延時(shí)了 1 秒執(zhí)行,當(dāng)然不會(huì)阻塞其他的代碼執(zhí)行膳沽。那么你可以試著將延時(shí)1000改為0汗菜,這就表示彈出框應(yīng)該是沒有延時(shí)立即執(zhí)行让禀,但是你會(huì)發(fā)現(xiàn)實(shí)際上還是先打印出test,再執(zhí)行了alert陨界。為什么會(huì)這樣呢巡揍?我們下面再說
在實(shí)際項(xiàng)目中,我們可以利用setTimeout的異步特性菌瘪,解決一些問題腮敌,比如某個(gè)對(duì)象還未實(shí)例化,為了保證該對(duì)象在使用到時(shí)能夠確保已經(jīng)被實(shí)例化俏扩,就可以通過setTimeout來實(shí)現(xiàn)
setTimeout 回調(diào)函數(shù)的執(zhí)行時(shí)機(jī)
現(xiàn)在我們來說說為什么延時(shí)設(shè)為 0 糜工,回調(diào)函數(shù)卻沒有立即執(zhí)行的問題
我們知道瀏覽器是基于事件循環(huán)的,其中會(huì)有多個(gè)隊(duì)列录淡,頁面的渲染是一個(gè)隊(duì)列捌木,js 代碼的執(zhí)行也是一個(gè)隊(duì)列

js 代碼執(zhí)行時(shí)會(huì)創(chuàng)建一系列的任務(wù),而這些任務(wù)秉承著先進(jìn)先出的原則被加入到隊(duì)列中嫉戚。但是setTimeout是特殊的钮莲,當(dāng)執(zhí)行到setTimeout時(shí),js會(huì)將其拿出來放到一個(gè)單獨(dú)的特殊隊(duì)列中彼水,這個(gè)隊(duì)列中的任務(wù)在 js 隊(duì)列還有未執(zhí)行完的任務(wù)時(shí)崔拥,永遠(yuǎn)不會(huì)被執(zhí)行
舉個(gè)不恰當(dāng)?shù)睦踝樱∶飨胪嬗螒蚍锔玻亲鳂I(yè)還沒做完链瓦,由于小明是單線程的,雖然現(xiàn)在很想玩游戲盯桦,但是他還是給自己設(shè)定了條件:作業(yè)不做完不能玩游戲慈俯,一做完立刻玩游戲(延時(shí)為0),于是玩游戲這個(gè)任務(wù)就被小明歸置到了一個(gè)特殊的任務(wù)隊(duì)列里面拥峦,在作業(yè)隊(duì)列所以任務(wù)完成之前不執(zhí)行特殊隊(duì)列里面玩游戲的任務(wù)贴膘,作業(yè)完成小明閑下來后立刻開始玩游戲(似乎有點(diǎn)啰嗦,但這不重要:)
所以只有瀏覽器的 js 引擎閑下來以后略号,才會(huì)執(zhí)行所有 setTimeout刑峡,即使延時(shí)為 0

var flag = true;
setTimeout(function() {
    flag = false;
}, 1000);
while(flag) {}
alert('this is an alert box');

問:上面的代碼什么時(shí)候會(huì)顯示彈出框?
答:永遠(yuǎn)都不會(huì)
上面的代碼中玄柠,while是一個(gè)耗時(shí)函數(shù)突梦,雖然setTimeout只延時(shí)了一秒執(zhí)行,但是由于主隊(duì)列中的while會(huì)永遠(yuǎn)的執(zhí)行下去羽利,所以setTimeout所在的隊(duì)列永遠(yuǎn)不會(huì)被執(zhí)行宫患,代碼會(huì)永遠(yuǎn)阻塞在while循環(huán)這邊
當(dāng)然,上面的這種無限循環(huán)在項(xiàng)目中不可能出現(xiàn)这弧,而代碼執(zhí)行速度極快娃闲,只要不出現(xiàn)十分耗時(shí)的代碼虚汛,定時(shí)器幾乎還是能夠按照我們的意愿在指定時(shí)間執(zhí)行回調(diào)函數(shù)
通過 setTimeout 優(yōu)化用戶體驗(yàn)
既然setTimeout必須等到主隊(duì)列中的任務(wù)執(zhí)行完以后才會(huì)執(zhí)行,那我們?cè)谂龅揭恍┦趾臅r(shí)的代碼時(shí)皇帮,是不是可以通過它來放在頁面的阻塞呢泽疆?
當(dāng)然是可以的,將耗時(shí)代碼寫進(jìn)setTimeout的回調(diào)玲献,時(shí)間設(shè)置為 0殉疼,這樣只要 js 引擎空閑下來就回去執(zhí)行這些耗時(shí)代碼,就不會(huì)阻塞頁面捌年,給用戶造成卡頓的體驗(yàn)瓢娜,提升用戶體驗(yàn)
不易察覺的危險(xiǎn)——內(nèi)存泄漏
什么是內(nèi)存泄漏?
一塊內(nèi)存在分配使用完畢以后礼预,既不會(huì)被再次使用眠砾,又沒有被及時(shí)回收,直到程序執(zhí)行完畢都始終占據(jù)著這塊內(nèi)存
setTimeout 什么情況會(huì)導(dǎo)致內(nèi)存泄漏托酸?
setTimeout的第一個(gè)參數(shù)可以是函數(shù)褒颈,也可以是字符串。當(dāng)傳入字符串時(shí)励堡,就會(huì)有內(nèi)存泄漏產(chǎn)生谷丸。先看下面兩個(gè)例子

setTimeout(function test1() {
    var a = 1;
    console.log(a);
}, 0)

setTimeout((function test2() {
    var b = 1;
    console.log(b);
}).toString(), 0)

// 1

執(zhí)行代碼后,打開控制臺(tái)应结,分別輸入函數(shù)名test1和test2

test1
// Uncaught ReferenceError: test1 is not defined

test2
// ... (打印出 test2 的函數(shù)體)

會(huì)發(fā)現(xiàn)刨疼,當(dāng)?shù)谝粋€(gè)參數(shù)為函數(shù)時(shí),回調(diào)函數(shù)執(zhí)行完畢后鹅龄,test1函數(shù)被銷毀揩慕,其所使用內(nèi)存也被釋放;當(dāng)?shù)谝粋€(gè)參數(shù)為字符串時(shí)扮休,test2卻始終存在迎卤,它沒有被銷毀,始終占據(jù)著內(nèi)存玷坠,也就造成了內(nèi)存泄漏
所以讓我們需要使用 setTimeout時(shí)蜗搔,一定要注意,第一個(gè)參數(shù)必須傳入一個(gè)函數(shù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末侨糟,一起剝皮案震驚了整個(gè)濱河市碍扔,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌秕重,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厉膀,死亡現(xiàn)場(chǎng)離奇詭異溶耘,居然都是意外死亡二拐,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門凳兵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來百新,“玉大人,你說我怎么就攤上這事庐扫》雇” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵形庭,是天一觀的道長(zhǎng)铅辞。 經(jīng)常有香客問我,道長(zhǎng)萨醒,這世上最難降的妖魔是什么斟珊? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮富纸,結(jié)果婚禮上囤踩,老公的妹妹穿的比我還像新娘。我一直安慰自己晓褪,他們只是感情好堵漱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著涣仿,像睡著了一般怔锌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上变过,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天埃元,我揣著相機(jī)與錄音,去河邊找鬼媚狰。 笑死岛杀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的崭孤。 我是一名探鬼主播类嗤,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼辨宠!你這毒婦竟也來了遗锣?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤嗤形,失蹤者是張志新(化名)和其女友劉穎精偿,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡笔咽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年搔预,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片叶组。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拯田,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出甩十,到底是詐尸還是另有隱情船庇,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布侣监,位于F島的核電站鸭轮,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏达吞。R本人自食惡果不足惜张弛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望酪劫。 院中可真熱鬧吞鸭,春花似錦、人聲如沸覆糟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽滩字。三九已至造虏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間麦箍,已是汗流浹背漓藕。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留挟裂,地道東北人享钞。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像诀蓉,于是被迫代替她去往敵國(guó)和親栗竖。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354