頁(yè)面中實(shí)現(xiàn)setInterval和setTimeout效果示例詳解
前言
昨天面試一家公司,面試官問(wèn)我,如何在不使用setTimeout和setInterval在頁(yè)面中實(shí)現(xiàn)setInterval和setTimeout效果,我:????。
后來(lái)我仔細(xì)想了一下,思路就是獲取時(shí)間戳,然后用遞歸判斷實(shí)現(xiàn)。那么思路是這樣,下面就代碼實(shí)現(xiàn)一下吧。
setTimeout的實(shí)現(xiàn)
function setTimeout_(dalay) { // 第一次的時(shí)間戳 const timestampFirst = Date.now() // 返回一個(gè)promise對(duì)象 return new Promise(reslove => { // 操作 function handle() { // 每一次的時(shí)間戳 const timestamp = Date.now() // 當(dāng)時(shí)間戳減去后大于延遲時(shí)間 if ((timestamp - timestampFirst) >= dalay) { // 成功回調(diào) reslove() } else { // 遞歸 handle() } } // 初次調(diào)用 handle() }) } setTimeout_(10).then(() => { alert(10) })
上面的代碼看似沒(méi)有毛病,但是運(yùn)行后發(fā)現(xiàn),setTimeout_()
里面的值設(shè)置小一點(diǎn)沒(méi)有問(wèn)題(比如2、3),但是一旦超過(guò),就會(huì)造成堆棧溢出,乃至報(bào)錯(cuò)。
解決堆棧溢出方法
下面隆重介紹一個(gè)人,蹦床函數(shù)(trampoline)
蹦床函數(shù)(trampoline)就是將 遞歸執(zhí)行 轉(zhuǎn)為 循環(huán)執(zhí)行。
執(zhí)行的都是同樣的步驟,只是反復(fù)執(zhí)行,就好像在蹦床,跳上去,掉下來(lái),在跳上去…
- 蹦床函數(shù)的實(shí)現(xiàn):
function trampoline(f){ while(f && f instanceof Function && falg){ f = f() } return f }
它接受一個(gè)函數(shù)f作為參數(shù)。只要f執(zhí)行后返回一個(gè)函數(shù),就繼續(xù)執(zhí)行。注意,這里是返回一個(gè)函數(shù),然后執(zhí)行該函數(shù),而不是函數(shù)里面調(diào)用函數(shù),這樣就避免了遞歸執(zhí)行,從而就消除了調(diào)用棧過(guò)大的問(wèn)題
最終實(shí)現(xiàn)
// 定時(shí)器 function setTimeout_(dalay) { // 第一次的時(shí)間戳 const timestampFirst = Date.now() // 返回一個(gè) Promise 對(duì)象 return new Promise(reslove => { // 具體操作 function handle() { // 每一次的時(shí)間戳 const timestamp = Date.now() // 當(dāng)時(shí)間戳減去后大于延遲時(shí)間 if ((timestamp - timestampFirst) >= dalay) { // 成功回調(diào) reslove() } else { // 不滿足條件繼續(xù)調(diào)用 return handle } } // 調(diào)用蹦床函數(shù)、將遞歸變?yōu)檠h(huán) trampoline(handle)() }) } // 蹦床函數(shù) function trampoline(f){ while(f && f instanceof Function){ f = f() } return f } setTimeout_(1000).then(res => { alert(1000) })
以上的代碼,就能實(shí)現(xiàn)效果了
思路:定義一個(gè)函數(shù),參數(shù)為延遲時(shí)間,調(diào)用時(shí)記錄一個(gè)第一次時(shí)間戳,然后里面返回一個(gè)Promise對(duì)象,再里面有一個(gè)閉包,是執(zhí)行遞歸操作的函數(shù),這個(gè)函數(shù)里面做的事就是記錄每一次的時(shí)間戳,然后減去第一次的時(shí)間戳,得出的就是間隔時(shí)間,跟規(guī)定的間隔時(shí)間作比較,如果大于的話,就調(diào)用Promise成功回調(diào)。再下面就是將遞歸轉(zhuǎn)為循環(huán),防止堆棧溢出。最后調(diào)用
setInterval的實(shí)現(xiàn)
這個(gè)跟setTimeout差不多,區(qū)別就是這個(gè)需要每隔一段時(shí)間執(zhí)行代碼,并且需要手動(dòng)清除
// 如果 falg 為 false就不會(huì)繼續(xù)執(zhí)行循環(huán)操作 let falg = true // 蹦床函數(shù)技術(shù),利用循環(huán) function trampoline(f){ while(f && f instanceof Function && falg){ f = f() } return f } // 計(jì)時(shí)器 function setInterval_(f, dalay) { // 第一次的時(shí)間戳 let timestampFirst = Date.now() // 操作 function handle() { // 每一次的時(shí)間戳 const timestamp = Date.now() if ((timestamp - timestampFirst) >= dalay) { // 間隔時(shí)間到了就重置第一次時(shí)間戳 timestampFirst = Date.now() // 調(diào)用函數(shù) f() } return handle } trampoline(handle)() } let count = 0 // 調(diào)用 setInterval_(function() { count ++ if (count === 3) { falg = false } console.log(count) }, 1000)
上面這個(gè)代碼我定義的是在控制臺(tái)輸入1、2、3,然后關(guān)閉
思路:同樣是判斷時(shí)間戳,但是跟setTimeout不一樣的是每次執(zhí)行里面的函數(shù)需要重置時(shí)間,達(dá)到每次執(zhí)行的效果。并且在蹦床函數(shù)里面的while增加一個(gè)判斷,用來(lái)控制計(jì)時(shí)器的停止。
總結(jié):這種東西了解一下,以后當(dāng)個(gè)吹牛逼資本就可以了,畢竟這性能嘛.....
以上就是頁(yè)面中實(shí)現(xiàn)setInterval和setTimeout效果示例詳解的詳細(xì)內(nèi)容,更多關(guān)于setInterval setTimeout頁(yè)面效果的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
JS圖片懶加載技術(shù)實(shí)現(xiàn)過(guò)程解析
這篇文章主要介紹了JS圖片懶加載技術(shù)實(shí)現(xiàn)過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07無(wú)間斷滾動(dòng)的新聞文章列表,兼容IE、Firefox和Opera,符合W3C標(biāo)準(zhǔn)??勺鱉arquee
無(wú)間斷滾動(dòng)的新聞文章列表,兼容IE、Firefox和Opera,符合W3C標(biāo)準(zhǔn)??勺鱉arquee...2007-05-05ClearTimeout消除閃動(dòng)實(shí)例代碼
本文給大家介紹ClearTimeout消除閃動(dòng)相關(guān)知識(shí),本文介紹的非常詳細(xì),具有參考借鑒價(jià)值,感興趣的朋友一起學(xué)習(xí)吧2016-02-02ES6中Array.copyWithin()函數(shù)的用法實(shí)例詳解
ES6為Array增加了copyWithin函數(shù),用于操作當(dāng)前數(shù)組自身,用來(lái)把某些個(gè)位置的元素復(fù)制并覆蓋到其他位置上去。下面重點(diǎn)給大家介紹ES6中Array.copyWithin()函數(shù)的用法,需要的朋友參考下2017-09-09bootstrap為水平排列的表單和內(nèi)聯(lián)表單設(shè)置可選的圖標(biāo)
為水平排列的表單和內(nèi)聯(lián)表單設(shè)置可選的圖標(biāo)。本文通過(guò)示例代碼給大家講解,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧2017-02-02不依賴Flash和任何JS庫(kù)實(shí)現(xiàn)文本復(fù)制與剪切附源碼下載
本篇文章給大家分享的文本復(fù)制與剪切板功能,實(shí)現(xiàn)此功能不依賴falsh插件和任何js庫(kù)實(shí)現(xiàn)的,感興趣的朋友一起看看吧2015-10-10JavaScript使用百度ECharts插件繪制餅圖操作示例
這篇文章主要介紹了JavaScript使用百度ECharts插件繪制餅圖操作,結(jié)合實(shí)例形式分析了JavaScript使用百度ECharts插件繪制餅圖的原理、步驟及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-11-11JS中call和apply函數(shù)用法實(shí)例分析
這篇文章主要介紹了JS中call和apply函數(shù)用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了call和apply函數(shù)繼承功能的使用方法、區(qū)別及操作注意事項(xiàng),需要的朋友可以參考下2018-06-06基于JS制作一個(gè)網(wǎng)頁(yè)版的猜數(shù)字小游戲
這篇文章主要為大家詳細(xì)介紹了如何利用HTML+CSS+JavaScript實(shí)現(xiàn)一個(gè)簡(jiǎn)單的網(wǎng)頁(yè)版的猜數(shù)字小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-07-07