摘要:高級(jí)定時(shí)器高級(jí)技巧異步首先,中沒(méi)有代碼是立即執(zhí)行的,而是一旦進(jìn)程空閑則立即執(zhí)行。針對(duì)第二種問(wèn)題,使用定時(shí)器是解決方法之一。為定時(shí)器設(shè)定的時(shí)間間隔使得進(jìn)程有時(shí)間在處理項(xiàng)目的事件之間轉(zhuǎn)入空閑。該函數(shù)首先清除之前設(shè)置的任何定時(shí)器。
title: 高級(jí)定時(shí)器
date: 2016-12-13
tag: JS高級(jí)技巧
首先,JavaScript 中沒(méi)有代碼是立即執(zhí)行的,而是一旦進(jìn)程空閑則立即執(zhí)行。
進(jìn)程何時(shí)空閑,取決于上一個(gè)執(zhí)行隊(duì)列的執(zhí)行時(shí)間,而與此對(duì)應(yīng)的是隨著頁(yè)面中生命周期的推移而產(chǎn)生的代碼執(zhí)行順序隊(duì)列。
定時(shí)器對(duì)隊(duì)列的工作方式是,當(dāng)設(shè)定的時(shí)間過(guò)去以后將代碼插入隊(duì)列,但不代表代碼會(huì)被立即執(zhí)行。
0x01 重復(fù)定時(shí)器很多情況下,我們都需要使用 setInterval() 重復(fù)的執(zhí)行同一段代碼去做同一件事情,而在這時(shí),最大的問(wèn)題在于定時(shí)器可能在代碼再次被添加到隊(duì)列之前還沒(méi)有被執(zhí)行完成,從而導(dǎo)致某些間隔被跳過(guò)或者多個(gè)定時(shí)器的代碼執(zhí)行時(shí)間間隔被縮短。
為了避免以上缺點(diǎn),可以使用鏈?zhǔn)秸{(diào)用 setTimeout() 模式
setTimeout(function(){ // do something setTimeout(arguments.callee, interval); }, interval)
一個(gè)例子:
setTimeout(function(){ $("#block").css({ "left": $("#block").position().left -1, }) if($("#block").position().left > 0){ setTimeout(arguments.callee, 30); } }, 30)0x01 數(shù)組分塊
為了防止惡意程序猿將用戶的計(jì)算機(jī)搞掛,瀏覽器對(duì) JavaScript 能夠使用的資源進(jìn)行了限制,如果代碼的運(yùn)行時(shí)間超過(guò)特定時(shí)間或者特定語(yǔ)句數(shù)量就不讓其繼續(xù)運(yùn)行。
而腳本運(yùn)行時(shí)間過(guò)長(zhǎng)的兩個(gè)主要原因是:1)過(guò)長(zhǎng),過(guò)深嵌套的函數(shù)調(diào)用;2)進(jìn)行大量處理的循環(huán)。
針對(duì)第二種問(wèn)題,使用定時(shí)器是解決方法之一。使用定時(shí)器分隔循環(huán),是一種叫作 數(shù)組分塊(array chunking) 的技術(shù)。
在數(shù)組分塊模式中,array 變量本質(zhì)上就是一個(gè) “代辦事項(xiàng)” 列表,它包含了要處理的項(xiàng)目,而 shift() 可以獲取隊(duì)列中下一個(gè)要處理的項(xiàng)目,然后將其傳遞個(gè)某個(gè)函數(shù)。當(dāng)隊(duì)列中還剩下其它項(xiàng)目時(shí),則設(shè)置另一個(gè)定時(shí)器,并通過(guò) arguments.callee 調(diào)用同一個(gè)匿名函數(shù)。
function chunk(array, process, context){ setTimeout(function(){ var item = array.shift() process.call(context, item) if(array.length > 0){ setTimeout(arguments.callee, 100) } }, 100) }
chunk() 方法接收三個(gè)參數(shù): 要處理項(xiàng)目的數(shù)組,用于處理項(xiàng)目的函數(shù),可選的運(yùn)行該函數(shù)的環(huán)境。
在函數(shù)內(nèi)部,通過(guò) call() 調(diào)用 process() 函數(shù),這樣可以設(shè)置一個(gè)合適的執(zhí)行環(huán)境。為定時(shí)器設(shè)定的時(shí)間間隔使得 JavaScript 進(jìn)程有時(shí)間在處理項(xiàng)目的事件之間轉(zhuǎn)入空閑。
調(diào)用實(shí)例:
var data = [12,124,343,56,76767,43,654,34645,56456,767,4645] function printValue(item){ var div = $("#block").html() $("#block").html(div + item + "
") } chunk(data, printValue)
如上,函數(shù) printValue() 將 data 數(shù)組中的每個(gè)值輸出到一個(gè) div 元素中。由于函數(shù)處于全局作用域中,因此無(wú)需給 chunk() 函數(shù)傳遞 context 對(duì)象。
如果想保持原數(shù)組不變,則應(yīng)將該數(shù)組的克隆傳遞給 chunk()
chunk(data.concat(), printValue)
調(diào)用某個(gè)數(shù)組的.contact(),如果不傳遞任何參數(shù),將返回和原來(lái)數(shù)組中項(xiàng)目一樣的數(shù)組。
0x02 函數(shù)節(jié)流函數(shù)節(jié)流 的基本思想是指,某些代碼不可以在沒(méi)有間斷的情況下連續(xù)重復(fù)的執(zhí)行。
瀏覽器中某些計(jì)算和處理的代價(jià)要比其他的昂貴很多,比如,DOM 操作比非 DOM 交互需要更多的內(nèi)存和 CPI 時(shí)間,而進(jìn)行過(guò)多的 DOM 相關(guān)操作可能導(dǎo)致瀏覽器掛起甚至崩潰,對(duì)于這種問(wèn)題,可以使用定時(shí)器對(duì)函數(shù)進(jìn)行節(jié)流。
函數(shù)節(jié)流的基本模式可以簡(jiǎn)化如下:
function throttle(method, context){ clearTimeout(method.tId) method.tId = setTimeout(function(){ method.call(context) }, 100) }
throttle() 函數(shù)接收兩個(gè)參數(shù): 要執(zhí)行的函數(shù)以及在哪個(gè)作用域中執(zhí)行。該函數(shù)首先清除之前設(shè)置的任何定時(shí)器。定時(shí)器 ID 是存儲(chǔ)在函數(shù)的 tId 屬性中的,當(dāng)然,首次將方法傳遞給 throttle 函數(shù)可能并不存在該屬性。然后定義一個(gè)新的定時(shí)器,并將 ID 存儲(chǔ)在 tId 屬性中。而 call() 用來(lái)確保方法在適當(dāng)?shù)沫h(huán)境中執(zhí)行。如果沒(méi)有給出第二個(gè)參數(shù),那么就在全局作用域內(nèi)執(zhí)行該方法。
在 setTimeout() 中用到的函數(shù)其執(zhí)行環(huán)境總是 window
throttle 方法調(diào)用實(shí)例:
function resizeDiv(){ var div = document.querySelector("#block") div.style.height = div.offsetWidth + "px" } window.onresize = function(){ throttle(resizeDiv) }
如上,為了保證在 resize 事件中瀏覽不會(huì)進(jìn)行高頻率,或者多次計(jì)算,我們給 window.onresize 綁定了一個(gè)函數(shù),在該函數(shù)調(diào)用了 throttle 方法,從而在窗口大小發(fā)生改變的時(shí)候是 div#block 的高度與其寬度保持一致。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/91349.html
摘要:圖二解讀定時(shí)器可以在指定時(shí)間把定時(shí)器代碼加入待執(zhí)行隊(duì)列,但并不能保證代碼執(zhí)行時(shí)機(jī),待執(zhí)行隊(duì)列中的代碼要等進(jìn)程空閑時(shí)才能執(zhí)行。也就是說(shuō)定時(shí)器每隔間隔觸發(fā)一次,嘗試加入隊(duì)列,擁堵時(shí)段將直接忽略本次操作。 圖片出自JS高程(第三版) showImg(https://segmentfault.com/img/bVbgC3V?w=1337&h=313); 圖一解讀:JS運(yùn)行于單線程的環(huán)境中:頁(yè)面...
摘要:關(guān)于定時(shí)器要記住的最重要的事情是指定的時(shí)間間隔表示何時(shí)將定時(shí)器的代碼添加到隊(duì)列,而不是何時(shí)實(shí)際執(zhí)行代碼。多個(gè)定時(shí)器之間的執(zhí)行間隔會(huì)比預(yù)期的小解決辦法處理中數(shù)組分塊,,函數(shù)節(jié)流,實(shí)際進(jìn)行處理的方法實(shí)際執(zhí)行的代碼初始處理調(diào)用的方法 一、高級(jí)函數(shù) 安全類型檢測(cè) Object.protitype.toString.call(value) 作用域安全的構(gòu)造函數(shù) function Pers...
摘要:下面通過(guò)幾個(gè)的定時(shí)器示例以及相關(guān)源碼來(lái)分析在中,功能到底是怎么實(shí)現(xiàn)的。我們知道,中的定時(shí)器并不同于計(jì)算機(jī)底層的定時(shí)中斷。補(bǔ)充資料在高級(jí)程序設(shè)計(jì)第三版第章高級(jí)技巧中對(duì)高級(jí)定時(shí)器以及有較詳細(xì)的討論。至此,這類定時(shí)器函數(shù)已經(jīng)可以為所用了。 上一篇博文提到,在Node中timer并不是通過(guò)新開線程來(lái)實(shí)現(xiàn)的,而是直接在event loop中完成。下面通過(guò)幾個(gè)JavaScript的定時(shí)器示例以及N...
摘要:和的定義是指多少時(shí)間之后將回調(diào)函數(shù)加入到的執(zhí)行隊(duì)列之中回調(diào)函數(shù)是否立即執(zhí)行取決于當(dāng)前的執(zhí)行隊(duì)列是否空閑。比較好的例子如下回調(diào)函數(shù)執(zhí)行其他操作假如內(nèi)部的執(zhí)行時(shí)間為那么的回調(diào)函數(shù)至少要等待才執(zhí)行。 1、惰性加載函數(shù) (判斷各個(gè)瀏覽器中是否支持某個(gè)屬性) function addEvent(elem, type, handler){ if(elem.addEventListener...
摘要:閉包閉包是指有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)當(dāng)某個(gè)函數(shù)被調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境及相應(yīng)的作用域鏈。要注意通過(guò)第句聲明的這個(gè)方法屬于構(gòu)造函數(shù)生成的對(duì)象,而不屬于構(gòu)造函數(shù)的變量對(duì)象,也就是說(shuō),并不存在于作用域鏈中。 看到評(píng)論里有仁兄建議我試試箭頭函數(shù),真是受寵若驚,本來(lái)寫這篇文章也只是想記錄寫要點(diǎn)給自己日后看的。今天早上看到一篇總結(jié)javascript中this的文章JavaScr...
閱讀 861·2021-10-14 09:43
閱讀 2189·2021-09-30 09:48
閱讀 3534·2021-09-08 09:45
閱讀 1170·2021-09-02 15:41
閱讀 1955·2021-08-26 14:15
閱讀 852·2021-08-03 14:04
閱讀 3042·2019-08-30 15:56
閱讀 3132·2019-08-30 15:52