在星球被問到鉤子函式的執行機理,感覺非常有必要用一篇專門的文章來闡述一下,OK,我們們快速的來過一下
一、什麼是鉤子
Vue 當中有鉤子函式,Git 的很多命令也有對應的 Hook,Webpack 的外掛機制也是基於“鉤子”,不知道你第一次聽到鉤子這個詞是在什麼地方,如果都有所瞭解的話,那麼更需要來思考一下這之間的聯絡,我是這麼理解的:
鉤子(hook)就是一些具有既定生命週期的框架工具,在生命週期的各個階段預留給使用者執行一些特定操作的口子,這其實是一種面向切面程式設計
這裡有兩個關鍵詞,既定的生命週期 和 面向切面
只有擁有既定的生命週期的框架工具才需要預留使用者自定義操作的口子,舉個簡單的栗子(對於不瞭解的同學好像也未必簡單):gulp 的工作方式是定義一個序列的任務管道流,你可以自由的拼接各種任務,這就叫做沒有既定的生命週期,這個時候鉤子毫無意義;但是 webpack 就不太一樣了,它已經定義好了分析、編譯、打包、輸出的整個工作流程,倘若你想在編譯結束之後打包輸出之前做一些事情,而 webpack 又不給你任何介入的鉤子,那你的任何努力都會白費,這就是鉤子的意義所在,還記得下面這兩張圖出自哪篇文章麼?
為什麼還要提到面向切面,我第一次聽到這個詞還是在寫 java 的時候,它是 spring 的核心思想之一(不得不說,前端從石器時代發展到今天的工業時代,大量借鑑了後臺的程式設計思想,所謂觸類旁通,那個道理就是這麼講來著)。發揮想象力,所謂的鉤子,是不是在框架工具的某個階段,切一刀,插入一個或者多個特定的操作,想不清楚的都面壁思過去~~
二、鉤子的執行機理
前面說了,鉤子就是在框架工具的某個階段插一刀,執行一個或者多個特定的操作,那不就是呼叫一個或者多個使用者定義的函式麼?
直接一點的,在框架工具生命週期的某個階段呼叫約定好的函式,例如 Vue,當元件渲染完畢,呼叫元件的 mounted 方法,當元件更新完畢,執行元件的 updated 方法
橫一點的,實現一套事件機制,在生命週期的某個階段,觸發特定的事件,執行註冊在該事件下的所有函式,說到事件,又有人頭皮發麻了,so,我又貼心的畫了一個圖:
事件的釋出訂閱機制的核心在於 事件池,訂閱事件的一方將具體的操作 push 到事件池的某個 key 值下面,釋出事件的一方,找到事件池的某個 key 值下訂閱的所有函式依次執行(函式之間也有可能有依賴關係),秉承
天下難事必作於易
的信念,如果將上述的事件池通過一個記憶體中的 hashMap 來表示,你應該就可以輕鬆的收入囊中了(類比Js的事件迴圈,其實只是用了獨立的執行緒來維護事件池)
其實很多框架工具的事件機制,還真的不過是一個 hashMap 來維護的那麼簡單,例如,Webpack 中採用的 Tapable
三、Tapable 介紹
之前在研究 webpack 的時候翻譯過 Tabpable 的文件,迄今為止,唯一的翻譯作品(尷尬~),由此去
四、後話
菲麥前端 是一個讓知識深入原理的知識社群,歡迎加微勾搭:facemagic2014