JS 奧義解析:模態框的設計

奧義是平凡中所蘊含的不凡,能有效地用於指導實踐

下定義react

首先咱們須要給模態框下一個定義,Wikipedia(這就是大名鼎鼎的維基百科,後續很是多的地方都會引用它的描述)稱其爲modal window或者modal dialog,我認爲modal dialog更加語義清晰,更具備語義化,由於一般模態框是須要用戶交互的,就像發起一個會話同樣。Wikipedia這樣描述:編程

The modal window is a child window that requires users to interact with it before it can return to operating the parent application, thus preventing the workflow on the application main window.

因此咱們能夠這樣理解:模態框是須要用戶優先處理的一次交互或者會話,優先處理在JavaScript中解釋爲阻斷線程,等待用戶作出響應(此處須要舉一反一地知道還應該有非模態框)。下定義的要義是要使你描述的事物區別於其餘,從而讓咱們可以明確這是模態框而不是一個橘子或者水杯。那麼模態框的實現必定要尊重其定義,或者說按照其定義實現。react-native

事實上全部JavaScript的功能都是這樣被定義而且實現的,只是咱們稱其爲標準,也許說ECMA-262你會更熟悉一些。若是你放開眼界,就會發現,人們對於下定義的運用遠不止於此,全世界都在絞盡腦汁已圖對其善加利用。數組

下定義的意義和運用瀏覽器

當咱們還在糾結於下定義的枯燥無味的時候,還在嫌棄的時候,咱們沒有意識到下定義不是全部人都有資格作的,只有那些最初的開創者和發現者才真正的有資格對他們開創和發現的東西下定義,命名也是同樣,還記得那句誰發現誰命名嗎?因此你在中學時候學到的無比嫌棄的說明文的下定義方法,其實其自己是至高的榮譽,而且只屬於不斷開拓的人(這個位置還應該觸類旁通的知道說明文還有那些經常使用的描述方法,由於他們竟然能夠和下定義並列,必定有神奇之處)。app

做爲普通人,對下定義的善加利用表如今你真正的理解某一個事物,由於只有你真正理解他的時候你才能正確的定義它。換位思考,若是你想知道你是否真正的理解了一個事物,最簡單的辦法就是給他下個定義。 舉個簡單的例子,JavaScript的數組有一個reduce方法,咱們能夠理解爲概括的意思,由於它跟數學概括法的前半部分很像,因而你能夠知道他是不斷的運用數組的每一項值推導出一個最終的結果,再因而你能夠猜到它應該有些什麼參數,再加上你的經驗記憶,你就能明確的知道它有些什麼參數,這就是聯想記憶法。dom

真正的聯想記憶法必定是推導而來的,運用的是一種歸一的思想,由於這正是計算機最初被設計的思想,它是二進制的,無論如今它的能力有多麼的強悍,最終都是能夠歸到0和1的。JavaScript也遵循這一規則,它歸於一切皆是對象。換位思考,整個JavaScript均可以由一切皆是對象推導出來,這原本是第一課,可是我們後面再來分析。異步

這時候咱們可能須要回顧一下咱們是如何經過對reduce下定義從而不斷推導、理解、而且運用這個方法的,這裏再也不贅述。ide

一樣,react-native 有一個新的方法或者概念叫作reducer,這個東西就不太好理解,並且是區別於數組reduce的概括的意思的,到目前爲止我沒法對它下一個特別明確的定義,而且這個定義能反應出它的設計思想。你們能夠運用下定義的方法對其進行更深刻的學習,共勉。函數

參考原生模態框實現

言歸正傳,儘管ECMA的文檔極盡艱難晦澀,但這倒是解決問題的通常方法,通常方法的共同特色都是自由散漫,簡單到你不相信他能發揮巨大的價值。將其用於抽象設計,這就是抽象設計的第一步—對你想實現的東西下一個定義。

因此咱們能夠這麼理解,爲了實現模態框的優先處理,JavaScript採用了阻塞線程的實現方式來100%防止代碼被繼續執行,直到用戶作出響應。既然JavaScript自身已經提供了模態框,而咱們盡然還要從新對其進行設計和封裝,那就不得不思考一下爲何咱們要這麼作了。解決這種二選一的爲何的最爲簡單而且行之有效的方法叫作swot分析。

那麼什麼叫作swot分析,現學現用,或者學以至用,咱們給他下一個定義,那就是權衡利弊,根據利大於弊或者弊大於利作出取捨。你的記憶中必定或多或少有這樣一句討厭的話:請分析一下你有什麼優點?有什麼缺點? 這時候你可能恍然大悟:靠,這不是三歲的時候跟小夥伴分餅乾所用的方法嗎? 是的,但這並不影響它成爲威震天下的swot分析法,這也正暗合通常方法的共同特色。很是多的重大決定就是這樣作出的。

那麼JavaScript實現的alert和confirm究竟有什麼問題呢?第一個問題就是它會阻塞線程,衆所周知,JavaScript是單線程的,線程資源是很是寶貴的,若是你熟悉JavaScript,你會知道JavaScript最經典的特性之一就是異步,固然異步也是由這個單線程執行了,這就更顯現出了這個線程的難得之處,絕不吝嗇的說,容不得半點浪費。固然,除此以外,醜是其次的,相比之下不值得提起(全部的相比內部實現都是由swot分析負責實現的)。能夠參照一個簡單的實例,定時2s以後執行一些事務(好比統計時間),但在設置定時以後馬上彈窗:

var startTime = Date.now();

function calculateElapsedTime()

{/*{{{*/

    var elapsedTime = (Date.now() - startTime)/1000;

    console.log('elapsedTime:', elapsedTime);

}/*}}}*/

setTimeout(calculateElapsedTime, 0);

alert('click ok to continue');

console.log('you will say this right after you click ok');

事實上這段代碼的全部console輸出都將被無限延期直到用戶處理完彈窗爲止。固然這段代碼表面看起來不夠簡潔,但它其實包含了很是多的細節,在這個匿名函數被濫用、塊級做用域缺失、語義化隨意的時代,有不少細節值得咱們深究,這部分咱們容後再討論。包括setTimeout的性能問題,以及JavaScript單線程所帶來的問題或者說能夠歸一到JavaScript單線程的問題。

至此咱們均可以看到,一個基本的訴求就是,在彈窗的同時JavaScript可能須要繼續執行它該執行的事務,由此能夠引伸的討論不少,相信不少人都遇到過彈窗的同時點不了回退按鈕,非得關掉彈窗才能回退,因此不少現代瀏覽器多了一個禁止再次彈框的複選框,在一些瀏覽器上,好比Safari(version 9.1.1),alert彈出的同時,console無法使用。

現代模態框的設計

改進了這種種以後(出現問題並進行不斷的改進,其實也就是當今互聯網快速迭代的核心驅動力之一),咱們但願的一個模態框是這樣的:

  1. 長得好看(看臉時代無需過多討論)

  2. 不阻塞線程,能夠一邊彈窗,一邊繼續執行任務跑得飛起

  3. 點擊回退按鈕無壓力後退,無需關閉已經出現的模態窗,特別在SPA應用中尤其重要

  4. 彈窗不能重疊(dom只有一套,實際上不會重疊,這裏指多個消息重疊時處理的靈活性)

  5. 須要在不關閉彈窗的基礎上更新呈現的消息以及處理措施

  6. 應該有統一的回收機制

繞過了線程阻塞,可讓咱們有更大的發揮空間,但請記住Linux申請權限時的經典名言:能力越大責任越大。擁有了一邊彈窗,一邊執行任務的能力以後,意味着你得清楚的知道哪些代碼應該在彈窗以前執行,哪些應該在彈窗後執行,哪些又該在彈窗的過程當中繼續執行,而且規劃好他們的結構。

爲了可以使彈窗不重疊,這裏須要引入隊列,全部彈窗以及相應的操做按隊列方式執行,這也就解釋了統一的回收機制,這就讓你有能力任什麼時候候清空隊列,回收全部彈窗,這也解釋了當有超過一個彈窗的時候,咱們能夠直接無閃爍更新內容和操做或者等待用戶操做以後順序彈窗(這裏的彈窗指alert和confirm)。讀到這裏,你可能恍然大悟,這不就是單例嗎,是的,可是同時你也得明白單例並無什麼特別之處,也不能取代你真正的設計和實現,由於你得記住,無論你怎麼設計和實現,最後你只申請一個實例,它就變成了單例(固然有一點你得清楚,不要重複添加dom節點)。

這些設計和實現細節無非是對咱們定義的模態框的設計和實現,固然它同時也是任務的分解,咱們常常在工做中或者會議上看到大領導提出目標,而後相應的負責人作任務分解,看起來和聽起來都索然無味,但這倒是作好事情相當重要的方法。雖然咱們抽象設計的過程跟公司或者企業的目標比起來微不足道,但作事的原理和方法是想通的。由於一個一樣簡單的道理,你得對這件事很是瞭解才能正確的作任務分解,而清晰的理解一般是作好這件事的關鍵,不管是追求巨大的目標仍是作簡單的抽象設計。

附言

程序是理性的,但寫程序的人是感性的,而奧義原本也是平凡中所蘊含的不凡,因此這一系列的文章將更加偏向理論、哲學,是用廣泛聯繫的思想來組織的,不只僅侷限於JavaScript,也不只僅只適用於編程,因此咱們假設看這一系列文章的人都擁有良好的JavaScript基礎,或者根本不關心語言自己。

相關文章
相關標籤/搜索