試著分析下正美大大的模板
https://github.com/RubyLouvre/mmTemplate/blob/master/mmTemplate.js
首先是一trim函數,把字符串兩端的空白字符去掉
然后是根據id獲取模板字符串,用ejs.compile(source)編譯成模版函數
最后用data來調用模版函數
這3步驟中有一些細節處理
用ejs.cache[id]緩存模版函數,防止重復編譯
$(id, doc)[0] || doc.querySelectorAll(id)[0] || doc.getElementById(id.slice(1)) 降級使用dom選擇器
針對 script textarea標簽內的文本進行unescape處理
opts對象用來配置
opts.doc 模板文檔對象
opts.tid 模板緩存id:string
opts.open tops.close 開始關閉標簽 默認 瀏覽器端為:"<&&>" nodejs端為:""
opts.[helpername] 在模板內部使用的自定義輔助函數
于是主要就是ejs.compile函數的編譯過程
首先對于其提供的模板例子
編譯函數根據分割符號<&&> 將其分割,現在用|||為大家標記出來如下:
|||= title() |||
|||= tr.name;; ||| | |||= tr.age; ||| | |||= tr.sex || "男" ||| | ||| } |||
這些由|||分割的片段被分為 普通字符串 和 js邏輯 兩大類
分割方法是設置一個標志位 flag=true
flag === true 的時候為普通字符串【默認值】
flag === false 的時候為js邏輯
由于<&&>是開始、閉合一一相對的,于是可以根據當前flag的值flag ? open : close去查找到下一個分隔符的開關類型和位置
普通 和 js邏輯字符串分別被存放于 codes和js數組中
同時,按照字符的順序同步進行的是把所有的字符串編譯成為一個匿名函數
先來一個時間字符串
var time = new Date * 1; // 1399372159719
匿名函數anonymous最終調用形式為anonymous(codes, js, filters, helpers)
于是編譯函數分別給 codes,js 映射了一個形式參數名 txt1399372159719, js1399372159719
現在匿名函數顯示如下:
function anonymous(txt1399372159719, js1399372159719, filters, title ) { return function(data) { "use strict"; try { var r = "", line1399372159719 = 0;
當遇到普通字符串的時候,會轉換成語句
r += txt1399372159719[index];
到遇到輔助函數<&= title() &>時轉換為:
r += title();
遇到<&- for(var i=0,tl = @trs.length,tr;i
for (var i = 0, tl = data.trs.length, tr; i < tl; i++) {;
其他類推
最終函數【格式化后】為:
function anonymous(txt1399372159719, js1399372159719, filters, title /**/ ) { return function(data) { "use strict"; try { var r = "", line1399372159719 = 0;; r += txt1399372159719[0];; line1399372159719 = 1;; r += title();; r += txt1399372159719[1];; line1399372159719 = 2; for (var i = 0, tl = data.trs.length, tr; i < tl; i++) {; r += txt1399372159719[2];; line1399372159719 = 3; tr = data.trs[i];; r += txt1399372159719[3];; line1399372159719 = 4;; r += tr.name;;;; r += txt1399372159719[4];; line1399372159719 = 5;; r += tr.age;;; r += txt1399372159719[5];; line1399372159719 = 6;; r += tr.sex || "男";; r += txt1399372159719[6];; line1399372159719 = 7; }; r += txt1399372159719[7];; line1399372159719 = 8;; r += txt1399372159719[8];; line1399372159719 = 9;; r += data.href;; r += txt1399372159719[9]; return r; } catch (e) { EJS.log(e); EJS.log(js1399372159719[line1399372159719 - 1]) } } }
注意到
生成的函數堪比手寫但有一些冗余的分號;防止語句沖突問題
trim=true的方式處理標簽冗余空白,適用于不需要生成多余空白的情況
@trs.length等語句會被轉化為 data.trs.length,而不是簡單的獲取全局變量
|過濾器會被收集起來,然后一個一個的執行順序嵌套執行
#注釋語句將被完全忽略
helpers是被數組化,然后按照形式參數一次被匿名函數調用的【參考title函數】
對于line1399372159719這個變量,我猜測是用于記錄編譯結果函數的行數的,具體還不是很明白,希望知道的同學可以幫忙解釋一下
這部分的代碼都位于js邏輯字符串分支的處理中
生成函數的方式為 Function.apply,這段代碼可以欣賞一下
var body = ["txt"+time,"js"+time, "filters"] var fn = Function.apply(Function, body.concat(helperNames,t) ); // console.log(fn.toString()) var args = [codes, js, EJS.filters]; var compiled = fn.apply(this, args.concat(helpers));
最后編譯函數被(緩存)返回,供我們調用 fn(data)
好厲害的代碼,我還要打個飽嗝再慢慢消化下。
特別是對于
line1399372159719 這個變量的作用 還在疑惑中,希望有人可以幫忙解釋下?
the End.
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/78088.html
摘要:為了幫助理解,我們繼續加日志司徒正美,加群一起研究與只要收到更新對象,就會被調度程序調用。渲染器在將來的某個時刻調用。導步肯定為歡迎加繼續略也是怒長,代碼的特點是許多巨型類,巨型方法,有之遺風。 insertUpdateIntoFiber 會根據fiber的狀態創建一個或兩個列隊對象,對象是長成這樣的 //by 司徒正美, 加群:370262116 一起研究React與anujs //...
摘要:司徒正美,加群一起研究與用于調整渲染順序,高優先級的組件先執行這只是一部分更新邏輯,簡直沒完沒了,下次繼續添上流程圖,回憶一下本文學到的東西 React16真是一天一改,如果現在不看,以后也很難看懂了。 在React16中,雖然也是通過JSX編譯得到一個虛擬DOM對象,但對這些虛擬DOM對象的再加工則是經過翻天覆地的變化。我們需要追根溯底,看它是怎么一步步轉換過來的。我們先不看什么組件...
摘要:很快沒在公司參考這么大的項目升級工作了。第二個是事件,這兩個事件無法冒泡,而的事件系統是建立在事件代理的基石之上。最大的收獲是,終于有高度可用的版本了,也有一個可以為自己代言的大項目,我們的調試技術又大大提高了二分法總是最有效的。 很快沒在公司參考這么大的項目升級工作了。工作的內容聽起來很簡單,將React改成我們平臺事業部的迷你React框架Qreact(https://github...
摘要:司徒正美的一款了不起的化方案,支持到。行代碼內實現一個胡子大哈實現的作品其實就是的了源碼學習個人文章源碼學習個人文章源碼學習個人文章源碼學習個人文章這幾片文章的作者都是司徒正美,全面的解析和官方的對比。 前言 在過去的一個多月中,為了能夠更深入的學習,使用React,了解React內部算法,數據結構,我自己,從零開始寫了一個玩具框架。 截止今日,終于可以發布第一個版本,因為就在昨天,我...
閱讀 4084·2023-04-26 01:48
閱讀 3258·2021-10-13 09:40
閱讀 1740·2021-09-26 09:55
閱讀 3614·2021-08-12 13:23
閱讀 1780·2021-07-25 21:37
閱讀 3432·2019-08-30 15:53
閱讀 1393·2019-08-29 14:16
閱讀 1397·2019-08-29 12:59