免费高清特黄a大片,九一h片在线免费看,a免费国产一级特黄aa大,国产精品国产主播在线观看,成人精品一区久久久久,一级特黄aa大片,俄罗斯无遮挡一级毛片

分享

!!!動(dòng)態(tài)界面:DSL&布局引擎

 quasiceo 2018-09-28

Jasonette 與 Tangram

很早的時(shí)候火了一陣子Jasonette,打出來的宣傳語是用json寫出純native的app(牛皮其實(shí)有點(diǎn)大,其實(shí)只是寫動(dòng)態(tài)界面,完全不是寫動(dòng)態(tài)App)。

前一陣子,天貓又開源了跨多個(gè)平臺(tái)的Tangram,一套通用的UI解決方案,仔細(xì)閱讀文檔我們會(huì)發(fā)現(xiàn),他們也是在用json來實(shí)現(xiàn)這套七巧板布局。一套靈活的跨平臺(tái)的UI解決方案。

Jasonette的牛皮其實(shí)有點(diǎn)大,很多人看到動(dòng)態(tài)用Json寫出純native的app,就很激動(dòng),仿佛客戶端也能有H5那樣的能力,但其實(shí)他只是focus在解決app中的界面的問題。Tangram的定位就很精準(zhǔn)了,是一套為業(yè)務(wù)出發(fā)的通用跨平臺(tái)UI解決方案,把布局渲染性能與多段一致性考慮在框架內(nèi)的UI框架。這二者有個(gè)共同點(diǎn)都是用json來描述界面與內(nèi)容,從而用native進(jìn)行呈現(xiàn),json這種數(shù)據(jù)是一種天然便于下發(fā)與動(dòng)態(tài)更新的數(shù)據(jù),因此這些其實(shí)都能讓客戶端做到類似H5網(wǎng)頁(yè)一樣的趕腳。雖然沒有使用WebView,但他們的設(shè)計(jì)思路和網(wǎng)頁(yè)技術(shù)的發(fā)展歷史如出一轍,因此@響馬大叔說過”這其實(shí)是最純正的網(wǎng)頁(yè)技術(shù),雖然他是native的”。

順著這個(gè)話題繼續(xù)問幾個(gè)問題

  • DSL

為什么Jasonette與Tangram都是用json?

  • 布局排版

為什么Jasonette寫出來的json有些屬性看著很像css?padding & align(拿Jasonette舉例)

  • 渲染

Jasonette調(diào)用UIKit進(jìn)行渲染,H5用WebView渲染,所以Jasonette就叫native?

從DSL說起

DSL 是 Domain Specific Language 的縮寫,意思就是特定領(lǐng)域下的語言,與DSL對(duì)應(yīng)的就是通用編程語言,比如Java/C/C++這種。換個(gè)通俗易懂的說法,DSL是為了解決某些特定場(chǎng)景下的任務(wù)而專門設(shè)計(jì)的語言。

舉幾個(gè)很著名的DSL的例子

  • 正則表達(dá)式

通過一些規(guī)定好的符號(hào)和組合規(guī)則,通過正則表達(dá)式引擎來實(shí)現(xiàn)字符串的匹配

  • HTML&CSS

雖然寫的是類似XML 或者 .{} 一樣的字符規(guī)則,但是最終都會(huì)被瀏覽器內(nèi)核轉(zhuǎn)變成Dom樹,從而渲染到Webview上

  • SQL

雖然是一些諸如 create select insert 這種單詞后面跟上參數(shù),這樣的語句實(shí)現(xiàn)了對(duì)數(shù)據(jù)庫(kù)的增刪改查一系列程序工作

計(jì)算機(jī)領(lǐng)域需要用代碼解決很多專業(yè)問題,往往需要同時(shí)具備編碼能力以及專業(yè)領(lǐng)域的能力,為了提高工作于生產(chǎn)效率,需要把一些復(fù)雜但更偏向?qū)I(yè)領(lǐng)域的處理,以一種更簡(jiǎn)單,更容易學(xué)習(xí)的語言或者規(guī)范(即DSL),抽象提供給領(lǐng)域?qū)<?,交給不懂編碼的領(lǐng)域?qū)<揖帉憽?/p>

然后代碼編程能力者通過讀取解析自己定制出來的這些語言規(guī)范,來領(lǐng)會(huì)領(lǐng)域?qū)<业囊鈭D,最終轉(zhuǎn)化成真正的通用編程語言代碼實(shí)現(xiàn),接入底層代碼框架,從而實(shí)現(xiàn)讓領(lǐng)域?qū)<抑恍枰獙W(xué)習(xí)更簡(jiǎn)單的DSL,就能影響代碼程序的最終結(jié)果。

(雖然DSL的原始定義是為了非編程的專業(yè)領(lǐng)域人才使用,但到后來直接交給程序員使用,但能大幅度提高程序員編寫效率的非通用語言,也被當(dāng)做是DSL的一種)

DSL在設(shè)計(jì)上的應(yīng)用

設(shè)計(jì)師會(huì)設(shè)計(jì)出很多精美的界面,最后交給程序員去用代碼編寫成漂亮的網(wǎng)頁(yè)或者App。每個(gè)界面如果純用代碼編寫,都會(huì)面臨大量的代碼工作量,這里面可能更多的是一些重復(fù)的機(jī)械性的代碼工作。諸如:某個(gè)元素設(shè)置長(zhǎng)寬,設(shè)置居中,設(shè)置文字,設(shè)置距離上個(gè)元素XX像素,N個(gè)元素一起縱向,橫向平均排列等等。對(duì)于代碼實(shí)現(xiàn)界面開發(fā)來說,程序員需要編寫一系列諸如:setFrame,setTitle,setColor,addSubview這樣的代碼,一邊寫這樣的代碼,一邊查閱設(shè)計(jì)師給出的各種標(biāo)注。

為了提高工作效率,如果能把一些設(shè)計(jì)師產(chǎn)出的長(zhǎng)寬,色值,文字,居中,距上等設(shè)計(jì)元數(shù)據(jù)(設(shè)計(jì)的標(biāo)注信息等),以一種約定的簡(jiǎn)潔的語言規(guī)則(即DSL)輸入給程序代碼,由程序和代碼自動(dòng)的分析和處理,從而生成真正的界面開發(fā)代碼setFrame,setTitle,setColor,addSubview,這樣就可以大幅度的減少代碼量與工作量,程序員來寫這種簡(jiǎn)潔的語法規(guī)則會(huì)更快更高效,甚至可以把這種簡(jiǎn)潔的語法規(guī)則教會(huì)設(shè)計(jì)師,讓設(shè)計(jì)師有能力直接寫出DSL,然后輸入給底層程序,這樣界面就自然完成。

做iOS客戶端開發(fā)的同學(xué)有興趣可以用文本編輯器打開以下XIB文件,你會(huì)看到我們拖來拖去拖線出來的Xib,其實(shí)就是XML語法,而Jasonette就是Json語法,他們用XML/JSON這種通用的結(jié)構(gòu)化語法來存儲(chǔ)這些設(shè)計(jì)數(shù)據(jù),用一些自定義的標(biāo)簽,來標(biāo)記這些數(shù)據(jù)的用途,XIB/JSON經(jīng)過解析后就會(huì)生成簽到字典的樹狀結(jié)構(gòu),因此代碼就可以進(jìn)行遍歷執(zhí)行,從而轉(zhuǎn)變成最終的UIKit的渲染代碼。

HTML/CSS,是網(wǎng)頁(yè)開發(fā)普遍使用的,他們也是一種DSL,你寫出的每一個(gè)HTML的DIV以及CSS的屬性樣式,最后都不是通過.html .css文件渲染到屏幕到瀏覽器上的,都是通過瀏覽器內(nèi)核最后調(diào)用OpenGL,C++代碼渲染上去的。從這個(gè)層面講,Jasonette客戶端框架用的json,native客戶端開發(fā)的XIB,與網(wǎng)頁(yè)瀏覽器的HTML/CSS是一回事。

XIB的XML代碼其實(shí)也一般不會(huì)交給設(shè)計(jì)師去學(xué)習(xí)和掌握,但是在XIB的XML基礎(chǔ)之上,制作出一個(gè)InterFaceBuilder,可以讓設(shè)計(jì)師用圖形界面拖來拖去,這種UI編輯器式的設(shè)計(jì)其實(shí)都離不開DSL,都是規(guī)劃出了一種比通用代碼語言更簡(jiǎn)潔的DSL后,再輔助開發(fā)界面編輯器生成這種簡(jiǎn)潔DSL來實(shí)現(xiàn)的。

Jasonette里的json如何工作

扯淡了這么多,親自看看Jasonette源碼是如何執(zhí)行DSL的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
{
"$jason": {
"head": {
"title": "{ ???????}",
"actions": {
"$foreground": {
"type": "$reload"
},
"$pull": {
"type": "$reload"
}
}
},
"body": {
"header": {
"style": {
"background": "#ffffff"
}
},
"style": {
"background": "#ffffff",
"border": "none"
},
"sections": [
{
"items": [
{
"type": "vertical",
"style": {
"padding": "30",
"spacing": "20",
"align": "center"
},
"components": [
{
"type": "label",
"text": "It's ALIVE!",
"style": {
"align": "center",
"font": "Courier-Bold",
"size": "18"
}
},
{
......省略
}
]
},{
......省略
},
{
"type": "label",
"style": {
"align": "right",
"padding": "10",
"color": "#000000",
"font": "HelveticaNeue",
"size": "12"
},
"text": "Watch the tutorial video",
"href": {
"url": "https://www./watch?v=hfevBAAfCMQ",
"view": "Web"
}
}
]
}
]
}
}
}

這是demo里的頁(yè)面json代碼,你會(huì)看到很多很像網(wǎng)頁(yè)開發(fā)的東西,head,body,padding,align等等,是不是覺得和CSS很像

這個(gè)demo寫的json文件其實(shí)就是一個(gè)helloworld界面,里面有一些按鈕,點(diǎn)擊可以跳轉(zhuǎn),還有一些圖片,我先簡(jiǎn)單介紹一下Jasonette DemoApp的啟動(dòng)流程

  • Application didFinishLaunchingWithOptions

程序初始化,觸發(fā)[[Jason client] start:nil],初始化Jason,在這個(gè)start里面,會(huì)創(chuàng)建JasonViewController,并且給這個(gè)VC設(shè)置rootUrl,設(shè)置這個(gè)VC作為Window的Key,從而進(jìn)行App展現(xiàn)

  • VC viewWillAppear

這個(gè)KeyVC,當(dāng)viewWillAppear的時(shí)候,觸發(fā)[[Jason client] attach:self],這個(gè)函數(shù)內(nèi)會(huì)調(diào)用[self reload]來進(jìn)行網(wǎng)絡(luò)數(shù)據(jù)拉取,剛剛說的rootUrl其實(shí)是一個(gè)json網(wǎng)絡(luò)文件(也可以設(shè)置成bundle內(nèi)文件),換句話說這個(gè)vc的json文件可以每次從網(wǎng)絡(luò)上拉取最新的json文件來實(shí)現(xiàn)動(dòng)態(tài)更新的(跟網(wǎng)頁(yè)實(shí)際上是一樣的),這個(gè)過程就是觸發(fā)網(wǎng)絡(luò)框架AF去拉取最新的json

  • AFNetworking download

在網(wǎng)絡(luò)數(shù)據(jù)拉取回來后,會(huì)經(jīng)過一系列的處理,包括請(qǐng)求異步的其他相關(guān)json(像不像異步請(qǐng)求其他css),把請(qǐng)求到的json字典經(jīng)過JasonParser這個(gè)類的一些其他處理最后生成最終的Dom字典(Dom這個(gè)詞寫在Jason drawViewFromJason的源碼里,源碼就將這個(gè)數(shù)據(jù)字典的變量起名叫dom,可見他做的和網(wǎng)頁(yè)工作原理是一個(gè)思路)

  • Jason drawViewFromJason 進(jìn)行主線程渲染

找到Jason類的drawViewFromJason:函數(shù),這才是我們DSL之所以能渲染成界面的最重要的一步,前面都是一直在下載DSL,處理DSL,結(jié)果就是json生成了最終需要的元數(shù)據(jù)字典–Dom字典,這一步就是將DSL轉(zhuǎn)變成App界面

Dom字典生成界面的過程

簡(jiǎn)單的看看這個(gè)流程都分別依次調(diào)用了哪些函數(shù),不一一講解了,最后我們挑最有代表的進(jìn)行說明。

  • [Jason drawViewFromJason:DomDic]

  • [JasonViewController reload:DomDic]

  • Set Stylesheet //CSS

  • [JasonViewController setupSections:DomDic]

  • [JasonViewController setupLayers:DomDic]

setupSections與setupLayers基本上涵蓋了頁(yè)面主元素的所有渲染方式

先以簡(jiǎn)單的setupLayers的代碼邏輯舉例,先按著約定的標(biāo)簽從Dom字典中有目的的讀取需要的數(shù)據(jù)字段Layers,循環(huán)遍歷Layers字段數(shù)組下的所有數(shù)據(jù),每一次都先判斷子節(jié)點(diǎn)的Type屬性,如果Type寫了Image,就會(huì)創(chuàng)建UIImageView,如果Type寫了Label,就會(huì)創(chuàng)建UILabel,根據(jù)子節(jié)點(diǎn)其他屬性一一設(shè)置不同的UIView的屬性,最后AddSubview到界面上。(我會(huì)略過大量實(shí)際代碼,以偽代碼形式進(jìn)行說明,實(shí)際代碼可以看源碼查看)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
NSArray *layer_items = body[@"layers"];
NSMutableArray *layers = [[NSMutableArray alloc] init];
//循環(huán)遍歷Dom樹下的layer字段
if(layer_items && layer_items.count > 0){
for(int i = 0 ; i < layer_items.count ; i++){
NSDictionary *layer = layer_items[i];
layer = [self applyStylesheet:layer];
//設(shè)置Css
//判斷type字段是否為image,是否有image url
if(layer[@"type"] && [layer[@"type"] isEqualToString:@"image"] && layer[@"url"]){
//NEW一個(gè)UIImageView
//設(shè)置UIImageView的style
//設(shè)置UIImageView的 image URL
//將UIImageView Add subview
//異步拉取圖片回來后,通過style,運(yùn)算UIImageView的frame
}
//判斷type字段是否為label,是否有text
else if(layer[@"type"] && [layer[@"type"] isEqualToString:@"label"] && layer[@"text"]){
//NEW一個(gè)TTTAttributedLabel
//設(shè)置TTTAttributedLabel的style
//設(shè)置文本
//addSubview
}
}
}

再說說setupSections,他其實(shí)充分利用了tableview的能力,首先將Dom字典下的sections字段進(jìn)行保存與整理,然后并不立刻進(jìn)行渲染,而是直接調(diào)用[UITableview reloadData],觸發(fā)heightForRowAtIndexPathcellForRowAtIndexPath。(我會(huì)略過大量實(shí)際代碼,以偽代碼形式進(jìn)行說明,實(shí)際代碼可以看源碼查看)

heightForRowAtIndexPath獲取cell高度

1
2
3
4
5
6
7
8
9
10
11
12
//取出indexPath.section對(duì)應(yīng)的dom節(jié)點(diǎn)數(shù)據(jù)
NSArray *rows = [[self.sections objectAtIndex:indexPath.section] valueForKey:@"items"];
//取出indexPath.row對(duì)應(yīng)的dom節(jié)點(diǎn)數(shù)據(jù)
NSDictionary *item = [rows objectAtIndex:indexPath.row];
//取出樣式屬性
item = [JasonComponentFactory applyStylesheet:item];
NSDictionary *style = item[@"style"];
//通過JasonHelper傳入style[@"height"]樣式屬性計(jì)算寬高
//一些樣式算法算出
return [JasonHelper pixelsInDirection:@"vertical" fromExpression:style[@"height"]];

cellForRowAtIndexPath獲取cell

1
2
3
4
5
6
7
8
9
10
11
NSDictionary *s = [self.sections objectAtIndex:indexPath.section];
NSArray *rows = s[@"items"];
//獲取對(duì)應(yīng)的Dom節(jié)點(diǎn)數(shù)據(jù)
iNSDictionary *item = [rows objectAtIndex:indexPath.row];
//渲染豎著滑的CELL
//只支持SWTableViewCell這一種客戶端預(yù)先寫好的這種通用cell
//支持Dom節(jié)點(diǎn)循環(huán)內(nèi)嵌stackview,按著內(nèi)嵌形式,橫豎布局都支持
//stackview內(nèi)的子元素通過JasonComponentFactory創(chuàng)建對(duì)應(yīng)的UIKit UIView
//創(chuàng)建方式如同layer,判斷type等于'image'創(chuàng)建UIImageView,判斷等于'text'創(chuàng)建UILabel
//frame通過style等字段,進(jìn)行系統(tǒng)autolayout計(jì)算
return [self getVerticalSectionItem:item forTableView:tableView atIndexPath:indexPath];

上面講的其實(shí)力度很粗,并且很多代碼沒有詳細(xì)展開,其實(shí)目的是讓大家發(fā)現(xiàn),Jasonette的源碼持續(xù)在干一件事情:

  • 從Dom字典中,讀取約定好的固定字段

  • 循環(huán)遍歷Dom字典,遍歷所有設(shè)計(jì)數(shù)據(jù)

  • 然后用字符串匹配去判斷每個(gè)節(jié)點(diǎn)的key與值,指引OC代碼應(yīng)該怎么調(diào)用

    • 匹配出label就創(chuàng)建UILabel

    • 匹配出iamge就創(chuàng)建UIImageView

    • 匹配出style就調(diào)用autolayout賦值屬性進(jìn)行autolayout計(jì)算,或者進(jìn)行自行算法計(jì)算。

Jasonette的DSL工作特點(diǎn)就是這樣,先從設(shè)計(jì)師給出的元數(shù)據(jù)入手,把所有的元數(shù)據(jù)抽象抽離出來,約定成固定的標(biāo)簽與值,然后客戶端一一遍歷整個(gè)Dom元數(shù)據(jù)的節(jié)點(diǎn),一一解讀這些標(biāo)簽與值,走入對(duì)應(yīng)的客戶端代碼,從而調(diào)用對(duì)應(yīng)的客戶端代碼功能。

客戶端的這套框架寫完之后,以后在寫全新的界面,其實(shí)是無需再重復(fù)寫一套客戶端代碼,而是直接寫全新的DSL也就是Jasonette的json文件就可以了。

DSL小結(jié)

拿JSON/HTML/CSS舉例子其實(shí),這些都是一種外部DSL,與之對(duì)應(yīng)的還有某些語言支持的內(nèi)部DSL,這里也就不展開了

Never’s Blog 外部DSL的實(shí)現(xiàn)

XML DSL
很多常見的XML配置文件實(shí)際上就是DSL,但不是所有的配置文件都是DSL。比如“屬性列表”和DSL是不同的,那只是一份簡(jiǎn)單的“鍵-值對(duì)”列表,可能再加上分類。
XML不是編程語言,是一種沒有語義的語法結(jié)構(gòu)。XML是DSL的承載語法,但是它又引入了太多語法噪音—太多的尖括號(hào)、引號(hào)和斜線,每個(gè)嵌套元素都必須有開始標(biāo)簽和結(jié)束標(biāo)簽。
自定義的外部DSL也帶來了一個(gè)煩惱:它們處理引用、字符轉(zhuǎn)義之類事情的方式總是難以統(tǒng)一。

所以DSL叫特殊領(lǐng)域語言,離開了為某一DSL專門開發(fā)的語言環(huán)境或者代碼框架,DSL是無法運(yùn)行的,沒有效果的,沒有正則表達(dá)引擎的源碼,你寫出來的正則表達(dá)式?jīng)]人認(rèn)識(shí)。沒有底層數(shù)據(jù)庫(kù)框架,sql語句就只是一行字符串,沒法進(jìn)行數(shù)據(jù)管理。沒有Jasonette這個(gè)框架,你寫出來json也不可能生成界面,有了Jasonette這個(gè)框架,你不按著約定的標(biāo)簽寫,自己?jiǎn)渭兊脑趈son里憑空創(chuàng)建標(biāo)簽,也是不可能正確生成你想要的東西。

在最后,筆者想說的是,當(dāng)我們?cè)谀骋粋€(gè)領(lǐng)域經(jīng)常需要解決重復(fù)性問題時(shí),可以考慮實(shí)現(xiàn)一個(gè) DSL 專門用來解決這些類似的問題。

from 談?wù)? DSL 以及 DSL 的應(yīng)用

布局與排版

既然說到動(dòng)態(tài)界面,那一定得聊屏幕適配,這其實(shí)不管是不是動(dòng)態(tài)界面,不管用不用到DSL,做客戶端都要考慮的一點(diǎn),其實(shí)網(wǎng)頁(yè)在這方面發(fā)展的更完善,畢竟客戶端的屏幕尺寸就那么幾種,就算安卓碎片化,也比不上PC電腦上,桌面瀏覽器用戶可以任意伸縮窗口的大小,因此對(duì)于在不同尺寸的限定屏幕大?。磁虐鎱^(qū)域)內(nèi),把設(shè)計(jì)出來的元素以最美觀的形式進(jìn)行展現(xiàn),這就是布局與排版。

剛才在講解DSL,講解Jasonette的時(shí)候其實(shí)回避一些問題,我們光提到了通過Dom的type信息,來創(chuàng)建不同的UIView,但是每一個(gè)UIView應(yīng)該擺放在屏幕的什么位置,在哪進(jìn)行展現(xiàn),在上面的文章中被一帶而過,有的描述,讀取style字段后分別賦值給對(duì)應(yīng)的autolayout,有的被我說成了進(jìn)行一定的算法從而算出高度。這背后其實(shí)都是布局與排版的算法。

做iOS客戶端的同學(xué)很多會(huì)有感觸,早些年的時(shí)候?qū)懡^對(duì)坐標(biāo),那時(shí)候iOS的屏幕尺寸還不是太多,用代碼手寫frame進(jìn)行元素定位,試想一下如果純用frame進(jìn)行app開發(fā),那么去開發(fā)一套對(duì)應(yīng)的DSL動(dòng)態(tài)界面其實(shí)更容易,我們只需要給每個(gè)字典節(jié)點(diǎn),規(guī)定上{x:N,y:N,w:N,h:N}的屬性,然后在框架里別的跟布局相關(guān)的style都不需要寫了,只需要用xywh生成CGRect,然后調(diào)用setFrame就好了,想開發(fā)出這樣一種絕對(duì)布局的動(dòng)態(tài)界面框架其實(shí)還真是挺簡(jiǎn)單的。

到后來有了iPad,有了iPhone5,有了iPhone6,6Plus,iOS的屏幕尺寸變的碎片化,如果繼續(xù)使用frame,客戶端同學(xué)開發(fā)工作量會(huì)變的異常繁瑣,于是在IOS7引入了蘋果的autolayout,引入了VFL語言Visual Format Language。其實(shí)VFL也應(yīng)該算是一種DSL吧,他不是用來繪制出一個(gè)個(gè)的界面元素,而是用來在繪制前,計(jì)算清楚每一個(gè)元素在動(dòng)態(tài)的屏幕區(qū)域下的最終位置。我們學(xué)會(huì)了如何寫VFL,或者說我們學(xué)會(huì)了如何用masnory這個(gè)框架實(shí)現(xiàn)autolayout,但我們并不需要深入去了解這里面的排版布局算法。

需要記住的一點(diǎn)是,最終渲染一定是通過frame去頁(yè)面上進(jìn)行繪制,有了明確的坐標(biāo)才能繪制出UI,手寫frame式的絕對(duì)布局代碼,直接由程序員指定,因此一定是性能開銷最小的,可以說沒有或者少量的布局運(yùn)算開銷直接進(jìn)行渲染,但在多屏適配的需求下才引入了一整套龐大的布局算法體系(不一定非得是蘋果的autolayout),引入龐大布局算法的目的是希望根據(jù)可排區(qū)域動(dòng)態(tài)的計(jì)算frame,但并不代表采用自動(dòng)布局,就與frame無關(guān),自動(dòng)布局算法只是間接的運(yùn)算出frame再渲染。

布局排版的流程圖

  • RenderTree parse
    • 瀏覽器內(nèi)核的方案是
      • 解析HTML,生成Dom
      • 解析CSS,生成style rules
      • attach Render Tree CSS與HTML掛載到一起
    • Jasonette的方案是
      • 反序列化Json,直接生成Dom字典
  • RenderTree layout
    • 從RenderTree RootNode 遍歷
    • 不同節(jié)點(diǎn)對(duì)應(yīng)調(diào)用不同layout算法
    • 運(yùn)算出每個(gè)可顯示界面元素的位置信息
  • RenderTree render
    • 遍歷Tree
    • 渲染

布局排版信息解析

  • 瀏覽器解析HTML/CSS 生成RenderTree

將HTML文件以字符串的形式輸入,經(jīng)過解析,生成了Dom樹,Dom樹就好比是iOS開發(fā)里面頁(yè)面View的層級(jí)樹,但是每個(gè)View/div里面并沒有css信息,只寫了每個(gè)div所對(duì)應(yīng)的css的名字

將CSS文件以字符串形式輸入,經(jīng)過解析,得到了一系列不同名字的style rules,樣式規(guī)則

Dom樹上的div并不包含樣式信息,而是只記錄了樣式的名字,然后從style rules里找到對(duì)應(yīng)名字的具體樣式信息,Attech到一起,生成了Render Tree渲染樹,此時(shí)的渲染樹只是Dom與CSS的合并,他依然不包含真正可以用于渲染的位置信息,因?yàn)樗€沒經(jīng)過布局排版。

  • Jasonette直接生成RenderTree

網(wǎng)頁(yè)將View的層級(jí),與View的樣式進(jìn)行了分離,View就是HTML,樣式是CSS,但是Jasonette的Json沒有做這樣的分離,Json直接描述的就是view與style歸并到一起的數(shù)據(jù),因此在Jasonette經(jīng)過了parse解析后直接就拿到了樣式與視圖的合體結(jié)構(gòu)信息。我們?cè)贘son里明顯可以看到head,footer,layers,sections這種字段其實(shí)就是HTML里面的類似Dom的對(duì)象,而style這個(gè)字段其實(shí)就是CSS里面的對(duì)象。Jasonette的源碼里直把這個(gè)字典起名叫 NSDictionary * dom,其實(shí)就可以感知到,雖然Jasonette使用的是json,但是他的思路跟瀏覽器內(nèi)核是一樣的。

  • iOS autolayout的操作過程

當(dāng)你使用代碼執(zhí)行addsubview的操作的時(shí)候,你其實(shí)就是在對(duì)一個(gè)view(一種節(jié)點(diǎn)),添加了一個(gè)子view(一個(gè)子節(jié)點(diǎn)),當(dāng)所有subview添加完成的時(shí)候,你已經(jīng)創(chuàng)建好了一個(gè)界面層級(jí)樹,你addSubview一個(gè)子view以后,會(huì)對(duì)這個(gè)view要么設(shè)置VFL,要么使用masnory,總之會(huì)對(duì)這個(gè)view設(shè)置樣式屬性(其實(shí)就是在用oc代碼,attach css),之后在layoutIfNeeded的時(shí)候,autolayout開始自己悶頭計(jì)算排版

換句話說iOS autolayout與HTML/CSS在解析上的區(qū)別是,iOS的布局是用代碼寫死的,生成一種界面層級(jí)樹形結(jié)構(gòu),而網(wǎng)頁(yè)HTML/CSS是用可隨意下發(fā)的字符串,進(jìn)行解析,從而生成了一種界面層級(jí)樹形結(jié)構(gòu)(RenderTree)

布局排版

無論使用的是網(wǎng)頁(yè),還是Jasonette,還是iOS autolayout,當(dāng)我們拿到?jīng)]有經(jīng)過排版的Render Tree的時(shí)候,雖然里面的節(jié)點(diǎn)包含著樣式信息,但是并沒有具體的繪制位置信息,因此需要從Tree的根節(jié)點(diǎn)開始依次遍歷每個(gè)節(jié)點(diǎn),每個(gè)節(jié)點(diǎn)都根據(jù)自己的樣式信息以及子節(jié)點(diǎn)的樣式信息進(jìn)行排版算法計(jì)算。

在排版引擎的設(shè)計(jì)模式里(一種設(shè)計(jì)概念,不是指具體某個(gè)排版源碼實(shí)現(xiàn)),一個(gè)RenderTree上每一個(gè)節(jié)點(diǎn)是一種RenderNode,他可能是不同的界面元素,甚至是界面容器,每個(gè)RenderNode都可以有自己的layout()方法用于計(jì)算自己和自己的子節(jié)點(diǎn)的算法,一個(gè)position絕對(duì)布局的節(jié)點(diǎn),他及內(nèi)部的子節(jié)點(diǎn)布局算法layout(),肯定與一個(gè)listview,tableview那種有規(guī)律的排布容器節(jié)點(diǎn)布局算法layout()不一樣,從根節(jié)點(diǎn)rootNode開始,循環(huán)遍歷遞歸下去,直到把Tree上的所有節(jié)點(diǎn)的位置信息都運(yùn)行了layout(),就完成了布局排版。

我們知道不同的節(jié)點(diǎn),是可以用不同的算法進(jìn)行他與內(nèi)部子節(jié)點(diǎn)的布局計(jì)算的。

拿iOS開發(fā)舉例子,我們完全可以同一個(gè)頁(yè)面內(nèi),有的view是用frame方式寫死的絕對(duì)布局,有的view是用masnory進(jìn)行的autolayout,甚至父view是寫死的絕對(duì)布局,子view是autolayou,或者反過來。

拿瀏覽器CSS來說,瀏覽器內(nèi)核C++代碼里一個(gè)RenderObject的基本子類之一就是RenderBox,該類表示遵從CSS盒子模型的對(duì)象,每一個(gè)盒子有四條邊界:外邊距邊界 margin edge, 邊框邊界 border edge, 內(nèi)邊距邊界 padding edge 與內(nèi)容邊界 content edge。這四層邊界,形成一層層的盒子包裹起來。這種基礎(chǔ)RenderBox有著自己的layout()算法。而在新的CSS里引入了更多不同的布局方式,比如運(yùn)用非常廣泛的Flexbox彈性盒子布局,Grid布局,多列布局等等。

在排版引擎的設(shè)計(jì)模式里,如果你想引入一種新的布局算法,或者一種新的專屬布局效果鎖對(duì)應(yīng)的布局計(jì)算,你只需要?jiǎng)?chuàng)建一種新的RenderNode,并且實(shí)現(xiàn)這種node的layout()函數(shù),你就可以為你的排版引擎,持續(xù)擴(kuò)展支持更多的排版能力了

Jasonette是怎么做的?

jasonette其實(shí)根本沒自己實(shí)現(xiàn)布局算法,也沒有抽象出renderNode這種樹狀結(jié)構(gòu),他直接用原始的Dom字典直接開始遍歷遞歸。

遍歷到layers節(jié)點(diǎn),就調(diào)用[JasonLayer setupLayers]函數(shù),內(nèi)部是自己寫的一套xywh的算法,有那么點(diǎn)像CSS盒子模型,但簡(jiǎn)單的多。

遍歷到sections節(jié)點(diǎn),就調(diào)用[JasonViewController setupSections]函數(shù),走系統(tǒng)的tableview的reload布局,在heightforrow的時(shí)候,用自己的一套算法計(jì)算高度,而在cellforrow的時(shí)候,他使用系統(tǒng)stackview與系統(tǒng)autolayoutAPI進(jìn)行設(shè)置,最后走系統(tǒng)autolayout布局

Jasonette的布局過程看起來很山寨,從設(shè)計(jì)上把Dom字典直接快速遍歷,識(shí)別標(biāo)簽,用if else直接對(duì)接到不同的iOS代碼里,有的布局代碼是一些簡(jiǎn)單盒子運(yùn)算,有的布局代碼則是直接接入系統(tǒng)autolayout,可以看出來他從DSL的角度,多快好省的快速實(shí)現(xiàn)了一個(gè)界面DSL框架,但從代碼架構(gòu)設(shè)計(jì)的角度上,他距離完善龐大的排版引擎,從模塊抽象以及功能擴(kuò)展上,還欠缺不少。

布局排版的幾種算法

  • 絕對(duì)布局

這就不說了,固定精確的坐標(biāo),其實(shí)不需要計(jì)算了

  • iOS autolayout

從 Auto Layout 的布局算法談性能

Auto Layout 的原理就是對(duì)線性方程組或者不等式的求解。

這篇文章寫得非常非常清楚,我就不詳細(xì)展開了,簡(jiǎn)單的說一下就是,iOS會(huì)把父view,子view之間的坐標(biāo)關(guān)系,樣式信息,轉(zhuǎn)化成一個(gè)N元一次方程組,子view越多,方程組的元數(shù)越多,方程組求解起來越耗時(shí),因此運(yùn)算性能也會(huì)越來越底下,這一點(diǎn)iOS 的Auto Layout其實(shí)被廣泛吐槽,廣受詬病。

  • CSS BOX 盒子模型

傳統(tǒng)的CSS盒子模型布局,這個(gè)前端開發(fā)應(yīng)該是基本功級(jí)別的東西,可以自行查閱

  • FlexBox 彈性盒子

CSS3被引入的更好更快更強(qiáng)的強(qiáng)力布局算法FlexBox,因?yàn)槠鋬?yōu)秀的算法效率,不僅僅在瀏覽器標(biāo)準(zhǔn)協(xié)議里,被廣泛運(yùn)用,在natie的hyrbid技術(shù)方面,甚至純native技術(shù)里也被廣泛運(yùn)用。

Facebook的ASDK也用的是Flexbox,一套純iOS的完全與系統(tǒng)UIKit不同的布局方式

大前端Hybrid技術(shù)棧里,RN與Weex中都用的是FlexBox,阿里的另外一套LuaView用Lua寫熱更新app的方案也用的是FlexBox算法

由FlexBox算法強(qiáng)力驅(qū)動(dòng)的Weex布局引擎

  • Grid 布局

網(wǎng)格布局(CSS Grid Layout)淺談

CSS布局模塊

Grid布局被正式的納入了CSS3中的布局模塊,但似乎目前瀏覽器支持情況不佳,看起來從設(shè)計(jì)上補(bǔ)全了Flexbox的一些痛點(diǎn)。

  • 多列布局

CSS布局模塊

CSS3的新布局方式,效果就好像看報(bào)刊雜志那樣的分欄的效果。

渲染

經(jīng)過了整個(gè)排版過程之后,renderTree上已經(jīng)明確知道了每個(gè)節(jié)點(diǎn)/每個(gè)界面元素具體的位置信息,剩下的就是按著這個(gè)信息渲染到屏幕上。

  • Jasonette

Jasonette直接調(diào)用的addSubview來進(jìn)行view的繪制,Dom字典遍歷完了,view就已經(jīng)被add到目標(biāo)的rootview里面去了,渲染機(jī)制和正??蛻舳碎_發(fā)沒區(qū)別,完全交給系統(tǒng)在適當(dāng)?shù)臅r(shí)候進(jìn)行屏幕渲染。

  • ReactNative & Weex

ReactNative iOS源碼解析(二)

Weex 是如何在 iOS 客戶端上跑起來的

這兩個(gè)Link其實(shí)介紹了,RN與Weex也是通過addSubview的方式,調(diào)用原生native進(jìn)行渲染,在iOS上來說就是addSubview

  • WebKit

在繪制階段,瀏覽器內(nèi)核并不會(huì)直接使用RenderTree進(jìn)行繪制,還會(huì)進(jìn)一步將renderTree處理成LayerTree,遍歷這個(gè)LayerTree,將內(nèi)容顯示在屏幕上。

瀏覽器本身并不能直接改變屏幕的像素輸出,它需要通過系統(tǒng)本身的 GUI Toolkit。所以,一般來說瀏覽器會(huì)將一個(gè)要顯示的網(wǎng)頁(yè)包裝成一個(gè) UI 組件,通常叫做 WebView,然后通過將 WebView 放置于應(yīng)用的 UI 界面上,從而將網(wǎng)頁(yè)顯示在屏幕上。但具體瀏覽器內(nèi)核內(nèi)部的渲染機(jī)制是怎么工作的有什么弊端,還取決于各個(gè)瀏覽器的底層實(shí)現(xiàn)。

How Rendering Work (in WebKit and Blink)

從這里面可以詳細(xì)看出來,瀏覽器內(nèi)核的渲染其實(shí)是可以做到下面這些多種功能的,但不同平臺(tái),不懂瀏覽器內(nèi)核的支持能力不同,不是所有的WebView或者瀏覽器App都是同樣的性能與效果

  • 直接調(diào)用平臺(tái)的系統(tǒng)GUI API
  • 設(shè)計(jì)自己的高效的Webview圖形緩存
  • 設(shè)計(jì)多線程渲染架構(gòu)
  • 融入硬件加速
  • 圖層合成加速
  • WebGL網(wǎng)頁(yè)渲染

仔細(xì)想想,真正到渲染這一步,你需要做的都是操作CPU和GPU去計(jì)算圖形,然后提交給顯示器進(jìn)行逐幀繪制,webview與native其實(shí)殊途同歸。

native界面?動(dòng)態(tài)? 我們其實(shí)一直在聊的是瀏覽器內(nèi)核技術(shù)

@響馬大叔說過”這其實(shí)是最純正的網(wǎng)頁(yè)技術(shù),雖然他是native的”。

本文從Jasonette出發(fā),從這個(gè)號(hào)稱純native,又動(dòng)態(tài),又用json寫app的技術(shù)上入手,看看這native+動(dòng)態(tài)的巨大吸引力到底有多神奇,挖下來看一看。

我們看到了和瀏覽器內(nèi)核一脈相承的技術(shù)方案

  • 通過DSL,下發(fā)設(shè)計(jì)元數(shù)據(jù)信息

  • 構(gòu)建Dom樹

  • 遍歷Dom樹,排版(計(jì)算算法與接入autolayout)

  • 遍歷Dom樹,渲染(addsubview接入系統(tǒng)渲染)

瀏覽器內(nèi)核

Webkit瀏覽器內(nèi)核就是按著這樣的結(jié)構(gòu)分為2部分

  • WebCore

綠色虛線部分是WebCore,HTML/CSS都是以String的形式輸入,經(jīng)過了parse,attach,layout,display,最終調(diào)用底層渲染api進(jìn)行展現(xiàn)

  • JSCore(本文之前一直沒提)

紅色部分是JSCore,JS以string的形式輸入,輸入JS虛擬機(jī),形成JS上下文,將Dom的一些事件綁定到j(luò)s上,將操作Dom的api綁定到j(luò)s上,將一些瀏覽器底層native API綁定到j(luò)s上

動(dòng)態(tài)界面,其實(shí)就是瀏覽器內(nèi)核的WebCore

整個(gè)WebCore不是一個(gè)虛擬機(jī),他里面都是C++代碼,因此HTML/CSS在執(zhí)行效率上,從原理上講和native是一回事,沒區(qū)別。

而我們今天提到的動(dòng)態(tài)界面,無論是Jasonette還是Tangram,甚至把xib或者storyboard動(dòng)態(tài)下發(fā)后動(dòng)態(tài)展示,用iOS系統(tǒng)API就完全可以做到動(dòng)態(tài)界面(滴滴的DynamicCocoa里面提到把xib當(dāng)做資源動(dòng)態(tài)下發(fā)與裝載),其實(shí)都和瀏覽器內(nèi)涵的WebCore部分是一個(gè)思路與設(shè)計(jì),沒錯(cuò)。

  • Jasonette的設(shè)計(jì)思路和HTML/CSS是一回事
  • iOS的xib/storyboard的設(shè)計(jì)思路和HTML/CSS是一回事

動(dòng)態(tài)界面,可以界面熱更新,但不是app功能熱更新

本文從開頭到現(xiàn)在,重點(diǎn)圍繞著WebCore的設(shè)計(jì)思路,講了N多,但是看到Webkit結(jié)構(gòu)圖的時(shí)候,你會(huì)發(fā)現(xiàn),有個(gè)東西我始終沒提到過–JSCore,但我在開頭提到了一句話

Jasonette牛皮其實(shí)有點(diǎn)大,其實(shí)只是寫動(dòng)態(tài)界面,完全不是寫動(dòng)態(tài)App

界面動(dòng)態(tài)這個(gè)詞與App功能動(dòng)態(tài)有什么區(qū)別呢?

一個(gè)APP不僅僅需要有漂亮的界面,還需要有業(yè)務(wù)處理的邏輯。

  • 一個(gè)按鈕點(diǎn)擊后怎么響應(yīng)?
    • 是否要執(zhí)行一些業(yè)務(wù)邏輯,處理一些數(shù)據(jù),然后返回來刷新界面?
    • 是否要保存一些數(shù)據(jù)到本地存儲(chǔ)?
    • 是否要向服務(wù)器發(fā)起請(qǐng)求?
  • 服務(wù)器請(qǐng)求回來后怎么做?
    • 是否刷新數(shù)據(jù)和界面?
    • 發(fā)現(xiàn)服務(wù)器接口請(qǐng)求錯(cuò)誤,客戶端做業(yè)務(wù)處理?

Jasonette號(hào)稱是用json開發(fā)native app,但是json只是一種DSL,DSL是不具備命令和運(yùn)算的能力的,DSL被譽(yù)為一種聲明式編程,但這些業(yè)務(wù)邏輯運(yùn)算,DSL這種領(lǐng)域?qū)S谜Z言是不可能滿足的,他需要的是通用編程語言。

因此Jasonette對(duì)點(diǎn)擊事件的處理,其實(shí)就是一種路由,json的對(duì)象里面有個(gè)標(biāo)簽約定為action,action的值是一個(gè)url字符串,url指向另一個(gè)界面的json文件,也就是說,DSL可以把這個(gè)view的點(diǎn)擊事件寫死,一旦發(fā)生點(diǎn)擊,固定會(huì)跳轉(zhuǎn)到url所指向全新的json頁(yè)面,換句話說,這就是網(wǎng)頁(yè)開發(fā)的url跳轉(zhuǎn)href字段。

換個(gè)說法你就理解了,Jasonette在技術(shù)上相當(dāng)于用iOS的native代碼,仿寫了一個(gè)處于刀耕火種的原始時(shí)代的瀏覽器內(nèi)核思路,一個(gè)還沒有誕生js技術(shù),只是純HTML的超文本鏈接的上個(gè)世紀(jì)的瀏覽器技術(shù)。那個(gè)時(shí)候網(wǎng)頁(yè)里每一個(gè)超鏈接,點(diǎn)進(jìn)去都是一個(gè)新的網(wǎng)頁(yè)。

所以這不叫App功能動(dòng)態(tài),充其量只是界面動(dòng)態(tài)。

JSCore的引入給瀏覽器內(nèi)核注入了動(dòng)態(tài)執(zhí)行邏輯腳本代碼的能力,先不說腳本引擎執(zhí)行起來效率不如native,但腳本引擎至少是一個(gè)通用編程語言,通用編程語言就有能力執(zhí)行動(dòng)態(tài)的通用代碼(JS/LUA等),通用代碼比DSL有更強(qiáng)大的邏輯與運(yùn)算能力,因此可以更加靈活的擴(kuò)展,甚至還可以將腳本語言對(duì)接native,這就是webkit架構(gòu)圖里提到的jsbinding。

將腳本語言對(duì)接到本地localstorage,js就有了本地存儲(chǔ)能力,將腳本語言對(duì)接到network,js就有了網(wǎng)絡(luò)的能力,將腳本語言對(duì)接上dom api,js就有了修改WebCore Dom樹,從而實(shí)現(xiàn)業(yè)務(wù)邏輯二次改變界面的能力。

因此ReactNative & Weex 可以算作App功能動(dòng)態(tài),他們不僅僅巨有WebCore的能力,同時(shí)還巨有JSCore的能力(這里面其實(shí)有個(gè)區(qū)別,瀏覽器內(nèi)核的WebCore是純native環(huán)境C++代碼,不依賴js虛擬機(jī),但RN與Weex負(fù)責(zé)實(shí)現(xiàn)WebCore能力的代碼,都是js代碼,是運(yùn)行在虛擬機(jī)環(huán)境之下的,但他們的渲染部分是bridge到native調(diào)用的系統(tǒng)原生api,有興趣看我寫的RN源碼詳解吧,ReactNative iOS源碼解析(一),ReactNative iOS源碼解析(二)

阿里的LuaView我沒細(xì)看過源碼,但其實(shí)內(nèi)部機(jī)制和RN&WEEX沒啥區(qū)別,用的是FlexBox排版,但是選用的是Lua Engine這個(gè)腳本引擎,而非JSCore

在native動(dòng)態(tài)化的道路上,不論大家走哪條路,有一個(gè)共識(shí)還是大家都找到了的,那就是看齊Web的幾個(gè)標(biāo)準(zhǔn)。因?yàn)閃eb的技術(shù)體系在UI的描述能力以及靈活度上確實(shí)設(shè)計(jì)得很優(yōu)秀的,而且相關(guān)的開發(fā)人員也好招。所以,如果說混合開發(fā)指的是Native里運(yùn)行一個(gè)Web標(biāo)準(zhǔn),來看齊Runtime來寫GUI,并橋接一部分Native能力給這個(gè)Runtime來調(diào)用的話,那么它應(yīng)該是一個(gè)永恒的潮流。

from “站在10年研發(fā)路上,眺望前端未來”:讀后感

雖然有點(diǎn)扯遠(yuǎn)了,但是這句話確實(shí)又回到響馬叔的那個(gè)思路,Jasonette用json寫出native app,他的思路依然是web思路,RN用js寫出native app,也不能改變他一整套web技術(shù)的基因。一個(gè)界面最終渲染是以native系統(tǒng)級(jí)Api實(shí)現(xiàn),并不能說明什么,渲染只是龐大Web內(nèi)核技術(shù)的末端模塊,把末端渲染模塊換成native的,其實(shí)說明不了什么。

webview性能真的比native慢很多么?

這里就要強(qiáng)調(diào)一下了,瀏覽器內(nèi)核在界面這塊是純C++實(shí)現(xiàn),沒有使用任何虛擬機(jī),所謂的瀏覽器內(nèi)核下的Dom環(huán)境是純C++環(huán)境,也就是純native環(huán)境,所以瀏覽器在單次渲染性能上,不見得比native慢。

CSS的布局排版兼容很多種布局算法,有些算法在保證前端開發(fā)人員以高素質(zhì)高質(zhì)量的開發(fā)前提下,同樣的界面,其性能是完全可能碾壓autolayout的,所以單說布局這塊,webview也不見得慢。

webview的渲染的時(shí)候還存在很多異步資源加載,但這個(gè)問題是動(dòng)態(tài)能力帶來的代價(jià),啥都遠(yuǎn)端實(shí)時(shí)拉最新的資源當(dāng)然會(huì)這樣,如果在App下以hybrid的形式,內(nèi)置本地靜態(tài)資源,通過延遲更新本地資源緩存的方式,設(shè)計(jì)hybrid底層app框架,那么這種開銷也能減少。更何況瀏覽器新技術(shù)PWA也好SW也好都從瀏覽器層面深度優(yōu)化了WAP APP的資源與緩存。

webview性能慢的原因很多,多方面綜合來看確實(shí)很容寫出性能不佳的頁(yè)面,但話也不能絕對(duì)了,web技術(shù)所帶來的靈活多變,是會(huì)給業(yè)務(wù)帶來巨大收益的。在需要靈活多變,快速響應(yīng),敏捷迭代的業(yè)務(wù)場(chǎng)景下,web技術(shù)(泛指這類用web的思路做出來的范hybrid技術(shù))所帶來的優(yōu)勢(shì)也是巨大的

動(dòng)態(tài)界面沒那么神秘,意義并不在技術(shù)實(shí)現(xiàn)

Jasonette寫了這么多,雖然沒有深度剖析每一行源碼,但把他的實(shí)現(xiàn)思路講解了一下,其實(shí)自己實(shí)現(xiàn)一個(gè)動(dòng)態(tài)界面也不是不可以。

我們的工作業(yè)務(wù)需要深度處理文字,我們也有一套跨平臺(tái)的C++排版引擎內(nèi)核,思路是一脈相承的,區(qū)別是文字排版會(huì)比界面區(qū)塊盒子排版更復(fù)雜的多,用的也是json當(dāng)做DSL,但是我們利用我們的文字排版引擎,去實(shí)現(xiàn)相對(duì)簡(jiǎn)單的各種在native系統(tǒng)上的什么圖片環(huán)繞,圖文繞排,瀑布流界面UI等,其實(shí)非常的容易,甚至還是跨平臺(tái)的(比native代碼實(shí)現(xiàn)要容易的多)。就連Jasonette代碼里也就只支持section(tableview布局)和layer(盒子模型)2中常見形式,復(fù)雜頁(yè)面一樣實(shí)現(xiàn)不了。

但是!但是!但是!

DSL是領(lǐng)域?qū)I(yè)語言,DSL就注定巨有著局限性,你為自己的排版引擎設(shè)計(jì)出一套DSL規(guī)則,就算都使用的是json,那又如何,新來的一個(gè)人能很快上手寫出復(fù)雜頁(yè)面?DSL的規(guī)則越龐大,引擎支持的能力越強(qiáng),越代表著DSL的學(xué)習(xí)成本直線加大。

HTML/CSS已經(jīng)發(fā)展成為一個(gè)國(guó)際標(biāo)準(zhǔn),甚至是一種被廣泛傳播和學(xué)習(xí)的DSL,因此他有著很多技術(shù)資料,技術(shù)社區(qū),方便這門語言的發(fā)展,并且隨著應(yīng)用越廣,語言層面的抽象越來越合理,擴(kuò)展能力也越來越強(qiáng)。

但是你自己設(shè)計(jì)出來的DSL能走多遠(yuǎn)?能應(yīng)用多遠(yuǎn)?

  • 學(xué)習(xí)成本大,哪怕只是在自己業(yè)務(wù)內(nèi),也很大的,需要有效的建立文檔說明,維護(hù)業(yè)務(wù)迭代帶來的功能變化,還要給新來的同事培訓(xùn)如何寫這種DSL。

  • 應(yīng)用范圍小,想應(yīng)付自己一個(gè)業(yè)務(wù),可能初步設(shè)計(jì)出來的接口和功能就滿足需求了,但也只能自己使用,如果想推廣,必然會(huì)帶來更大的維護(hù)成本,需要更加精細(xì)化合理化的API設(shè)計(jì),擴(kuò)展性設(shè)計(jì)

  • 人員的遷移成本大,DSL的特點(diǎn)是會(huì)讓寫DSL的人員屏蔽對(duì)底層代碼的理解,甚至一些初中是為了能給一些不會(huì)編碼的專業(yè)領(lǐng)域人員學(xué)習(xí)和運(yùn)用,如果編程的人員長(zhǎng)時(shí)間寫這種專有的DSL,遷移到別的公司以后,該公司不用這種DSL,那么這些技能就徹底廢掉,如果開發(fā)者自身不保持一些對(duì)底層源碼的自行探索,那么換工作將會(huì)帶來很大的損失

前端人員在寫各種HTML/CSS的時(shí)候,想要深刻理解透其中的作用機(jī)制,也是需要深入到瀏覽器內(nèi)核層面去了解內(nèi)部機(jī)制的

所以我覺得天貓的Tangram,是很值得尊敬的,因?yàn)橄胱龀鲆粋€(gè)動(dòng)態(tài)界面框架,沒那么難,想做大,做到通用性,擴(kuò)展性,做到推廣,做到持續(xù)維護(hù),是非常艱難的,真的很贊!

參考文獻(xiàn)

談?wù)?DSL 以及 DSL 的應(yīng)用(以 CocoaPods 為例)

DSL(五)-內(nèi)部DSL vs 外部DSL (N篇系列文章)

由FlexBox算法強(qiáng)力驅(qū)動(dòng)的Weex布局引擎

從 Auto Layout 的布局算法談性能

CSS布局模塊

走進(jìn)Webkit

WebCore中的渲染機(jī)制(一):基礎(chǔ)知識(shí)

理解WebKit和Chromium: WebKit布局 (Layout)

瀏覽器渲染原理簡(jiǎn)介

ReactNative iOS源碼解析(二)

Weex 是如何在 iOS 客戶端上跑起來的

How Rendering Work (in WebKit and Blink)

“站在10年研發(fā)路上,眺望前端未來”:讀后感

ReactNative iOS源碼解析(一)

ReactNative iOS源碼解析(二)


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多