摘要:在這種惰性判斷里,我們利用了函數一等公民的身份和立即執行的便利,進行了初始判斷,隨后通過語句進行變量的重賦值,進而達到了性能上的提高。
常規的檢測方式在SPA、各種MV*框架如日中天,前后端分離、工程化大行其道的現如今來看,能力檢測似乎已經不那么重要,因為大多產品已經不再需要去兼容老舊的IE,或者說是更多偏向移動端的開發,雖然一些兼容的坑依舊存在,但是通過層出不窮的自動化工具,我們已經不必事事躬親了。然而今天要向大家分享的則是關于事件兼容性的能力檢測,可能看上去沒什么大的用場,卻是我們理解惰性函數的好途徑。
先看一則常見的事件監聽封裝
function addEvent(ele, type, cb, isCap) { if (window.addEventListener) { ele.addEventListener(type, cb, isCap); } else if (window.attachEvent) { ele.attachEvent(type, function () { var args = [].prototype.slice(0); window.event[target] = window.event.srcElement; args.unshift(window.event); cb.apply(this, args); }); } else { ele["on" + type] = cb; } } var body = document.body; addEvent(body,"load",function () { console.log("onload") // onload }); addEvent(body,"click",function () { console.log("onclick") // onclick });
可以看的到,這是一個有著足夠兼容性的的事件方法,能夠應付常見的需求和場面。
只是細細想來,當我們將這個方法復用了很多次后,會發現每次復用都會重新進行一次能力檢測,以便符合當前宿主環境。可能你會想,對于瀏覽器性能過剩的現如今來說,這點性能損耗并不算什么。
那么不妨做個假設,當我們在做一個高頻操作,例如window.onresize的監聽,鼠標隨便輕輕一拖,就可能會觸發無數次事件的重載。
面臨這種狀況,常規情況下,有經驗的開發者大致會做兩種處理來改善性能。
惰性檢測方式函數節流,將方法限頻,過濾一些線性重復性的操作。這方面,在loadash和underscore都有相應的方法。日后我也會分享出原生的實現方式。
從源頭找起,把不必要的能力檢測去除,我們只在頁面加載時檢測一次不好嗎?
函數節流我們日后再分享,那么,要如何把不必要的能力檢測去除掉呢?下面有兩種實現方式,代碼如下:
//使用惰性函數 var addEvent = (function () { //立即執行 if (window.addEventListener) { return function (ele, type, cb, isCap) { ele.addEventListener(type, cb, isCap); } } else if (window.attachEvent) { return function (ele, type, cb) { ele.attachEvent(type, function () { var args = [].prototype.slice(0); window.event[target] = window.event.srcElement; args.unshift(window.event); cb.apply(this, args); }); } } else { return function (ele, type, cb) { ele["on" + type] = cb; } //初始判斷過后,addEvent就無需再次判斷,已經是正確的封裝。 } }());
代碼變化并不大,關鍵點在于,我們用到了立即執行函數,即方法在初始化完畢,便立即判斷,判斷后,返回適合當前場景的方法。
//常見的方法調用方式 function getName() { console.log("ives") } getName() // ives;
//立即執行 可以是聲明函數 也可以是匿名函數 兩種方式均可 (function getName() { console.log("ives") // ives }());
在常見的高階函數實踐中,我們時常會接受函數,對函數的參數或者是上下文環境進行一些改造,并返回。在這種惰性判斷里,我們利用了函數一等公民的身份和立即執行的便利,進行了初始判斷,隨后通過return語句進行變量的重賦值,進而達到了性能上的提高。
實際上,很多常用的檢測,比如AJAX的封裝、獲取實際的CSS樣式等,都可以使用惰性函數處理。
重載檢測方式然而,這種方法也并非是完美的,我們假設另外一種場景,即是在靜態HTML中,我們引用的某個JS文件中有這個方法,但是這個HTML頁面并沒有事件性質的交互,那么我們可以基于吹毛求疵,雞蛋里挑骨頭的角度來斷言,這次惰性加載是失敗的,無用的。因為我們浪費了系統的資源,我們沒有事件,你為什么要加載一次?
總而言之,惰性加載雖然性能有提升,卻仍然不是最好的處理,只是有利于我們對于惰性函數的理解。
什么情景才是最完美的呢?即是初次調用時才做第一次判斷,隨后,無需判斷,方法也很簡單,只要簡單的改動幾行代碼。
依舊是以事件為例,代碼如下:
var addEvent = function (ele,type,cb,isCap) { //取消了立即執行 初次調用時進行方法重載 if (window.addEventListener) { addEvent = function (ele, type, cb, isCap) { ele.addEventListener(type, cb, isCap); } } else if (window.attachEvent) { addEvent = function (ele, type, cb) { ele.attachEvent(type, function () { var args = [].prototype.slice(0); window.event[target] = window.event.srcElement; args.unshift(window.event); cb.apply(this, args); }); } } else { addEvent = function (ele, type, cb) { ele["on" + type] = cb; } } //初次調用時,手動執行重載的方法 addEvent(ele,type,cb,isCap); };
可以看到實現的方式異常簡單,通過對方法的重載,并在初始執行時手動執行重載后的方法,滿足了我們上述的條件。
結束語可能大家會說,你個標題黨,最后一種重載的方式才是相對完美的方式,今天又為什么要講惰性函數呢?無外,拋磚引玉罷了,在鉆研設計模式時,是絕對離不開閉包和惰性函數的,今天則算是小小的熱身。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/89398.html
摘要:作用域安全的構造函數會首先確認對象是正確類型的實例,然后再進行更改,如下這樣就避免了在全局對象上意外更改或設置屬性。在多人協作的項目中,為了避免他們誤改了全局對象,也應使用作用域安全的構造函數。 博客原文地址:Claiyre的個人博客如需轉載,請在文章開頭注明原文地址 在JavaScript中,函數的功能十分強大。它們是第一類對象,也可以作為另一個對象的方法,還可以作為參數傳入另一個函...
摘要:在執行函數時,通過保存堆棧狀態,再保存堆棧跳出后返回位置的指針,最后對變量賦值。這看上去沒有問題,只要將值存在堆棧就搞定了。 1. 引言 本周精讀的文章是 V8 引擎 Lazy Parsing,看看 V8 引擎為了優化性能,做了怎樣的嘗試吧! 這篇文章介紹的優化技術叫 preparser,是通過跳過不必要函數編譯的方式優化性能。 2. 概述 & 精讀 解析 Js 發生在網頁運行的關鍵路...
摘要:函數是一等公民。其實閉包本身也是函數式編程的一個應用。劣勢不能算是嚴格意義上的函數式語言,很多函數式編程的特性并沒有。 隨著大前端時代的到來,在產品開發過程中,前端所占業務比重越來越大、交互越來越重。傳統的老夫拿起JQuery就是一把梭應付當下重交互頁面已經十分乏力。于是乎有了Angular,React,Vue這些現代框架。 但隨之而來的還有大量的新知識新名詞,如MVC,MVVM,Fl...
摘要:函數是一等公民。其實閉包本身也是函數式編程的一個應用。劣勢不能算是嚴格意義上的函數式語言,很多函數式編程的特性并沒有。 隨著大前端時代的到來,在產品開發過程中,前端所占業務比重越來越大、交互越來越重。傳統的老夫拿起JQuery就是一把梭應付當下重交互頁面已經十分乏力。于是乎有了Angular,React,Vue這些現代框架。 但隨之而來的還有大量的新知識新名詞,如MVC,MVVM,Fl...
摘要:更多描述可見文檔這種惰性求值的方法在很多模塊中都會使用,比如中的使用上與例子一致,如表單中的討論在大部分情況下,讓屬性具有惰性求值能力的全部意義就在于提升程序性能。當不需要這個屬性時就能避免進行無意義的計算,同時又能阻止該屬性重復進行計算。 起步 我們希望將一個只讀的屬性定義為 property 屬性方法,只有在訪問它時才進行計算,但是,又希望把計算出的值緩存起來,不要每次訪問它時都重...
閱讀 1456·2021-09-02 19:23
閱讀 1603·2021-08-11 11:19
閱讀 649·2019-08-30 15:55
閱讀 1661·2019-08-30 12:50
閱讀 2248·2019-08-30 11:23
閱讀 2188·2019-08-29 13:13
閱讀 1510·2019-08-28 18:13
閱讀 3347·2019-08-26 11:53