面的指令可用于綁定應用程序數據到HTML DOM元素的屬性。
S.No. | 名稱 | 描述 |
1 | ng-disabled | 禁用給定的控制 |
2 | ng-show | 顯示了一個給定的控制 |
3 | ng-hide | 隱藏一個給定的控制 |
4 | ng-click | 表示一個AngularJS click事件 |
ng-disabled 指令
添加ng-disabled屬性到一個HTML按鈕,并把它傳遞模型。綁定模型到復選框,來看看變化。
<input type="checkbox" ng-model="enableDisableButton">Disable Button
<button ng-disabled="enableDisableButton">Click Me!</button>12復制代碼類型:[html]
ng-show 指令
添加 ng-show 屬性到HTML按鈕,并把它傳遞到模型。該模型綁定復選框。
<input type="checkbox" ng-model="showHide1">Show Button
<button ng-show="showHide1">Click Me!</button>
1234復制代碼類型:[html]
ng-hide 指令
添加 ng-hide 屬性到HTML按鈕,并把它傳遞模型。該模型綁定復選框。
<input type="checkbox" ng-model="showHide2">Hide Button
<button ng-hide="showHide2">Click Me!</button>
1234復制代碼類型:[html]
ng-click 指令
添加ng-click屬性到一個HTML按鈕,更新模型。綁定模型到HTML如下所示。
<p>Total click: {{ clickCounter }}</p></td>
<button ng-click="clickCounter = clickCounter + 1">Click Me!</button>
開課吧廣場-人才學習交流平臺
紹
cJinja 是一個使用cpp編寫的輕量html模版解析庫,依賴 ejson 來實現模版的數據替換(在jinja中稱為context,上下文)。模版的語法基本與django jinja一致,功能還算豐富。源碼僅有700行,適合學習,覺得不錯的點個star吧。
(該程序為 https://github.com/HuangHongkai/tinyserver 中的一個模塊)
編譯
使用cmake來編譯,windows和linux下均可編譯。推薦使用clion作為IDE。
編譯成功后在build目錄下會有libcjinja.a和cjinja_test.exe這2個文件。libcjinja.a是靜態庫,cjinja_test.exe是一個簡單的測試程序。
運行測試程序后會出現output.html(該文件是tmp.html解析后的結果。)
已經完成的功能
需要注意,表達式之間不能含有空格,例如{{ 1 + 1 }}是非法的,而{{ 1+1 }}是合法的。
使用方法
1. 變量和變量索引
簡單的例子如下,
HtmlTemplate html("username:{{ username }}\n" "parm.list[1][2]: {{parm.list[1][2] }} \n" "parm.key: {{ parm.key }}", 1); // 參數1表示傳入的是模版字符串,0表示傳入的是文件名,默認為0 JSONObject obj = { {"username", 1234}, {"parm", { {"key", "cde"}, {"list", {1, {1,2.3, "abcd"}, "hahaha"}}, }} }; html.setValue(obj); cout << html.render() << endl << endl; /* 運行后打印如下 username:1234 parm.list[1]: abcd parm.key: cde */
HtmlTemplate是一個庫的主要類,構造函數為
explicit HtmlTemplate(const string& str, int flag = 0); // flag=0是str表示文件路徑,不為0是表示傳入的模版字符串
其中str參數為字符串,可以表示html模板原始串,也可也表示為文件的路徑,flag默認為0。
setValue 方法表示傳入數據給模版對象。
render() 方法表示將模版解析成字符串。
JSONObject來源于 ejson 庫,用來模擬python的dict,構造函數也比較容易看懂。
2. 列表迭代
HtmlTemplate html("{% for x in list %}{{ x }}\n{%endfor%}" "此時x已經是臨時變量了,不可以在打印了 {{x}}\n" , 1); JSONObject obj = OBJECT( KEYVALUE("list", LIST(1,2,3,4,5)) ); cout << html.setValue(obj).render() << endl << endl; /*運行后輸出如下 1 2 3 4 5 此時x已經是臨時變量了,不可以在打印了 */
注意到在迭代過程中x是作為臨時變量,在外部的話是無法打印出來的。
3. 字典迭代
HtmlTemplate html("{% for key in dict %}迭代1: 字典的key值為 {{ key }}\n{% endfor %}" "{% for key,value in dict %}迭代2: 字典的key值為 {{ key }}, value值為 {{ value}}\n{% endfor %}" "{% for ,value in dict %}迭代3: 字典的value值為 {{ value }}\n{% endfor %}", 1); JSONObject obj = OBJECT( KEYVALUE("dict", OBJECT( KEYVALUE("key1", "value1"), KEYVALUE("key2", 1234), KEYVALUE("key3", nullptr), )) ); cout << html.setValue(obj).render() << endl << endl; /*運行后輸出 迭代1: 字典的key值為 key1 迭代1: 字典的key值為 key2 迭代1: 字典的key值為 key3 迭代2: 字典的key值為 key1, value值為 value1 迭代2: 字典的key值為 key2, value值為 1234 迭代2: 字典的key值為 key3, value值為 null 迭代3: 字典的value值為 value1 迭代3: 字典的value值為 1234 迭代3: 字典的value值為 null */
4. 字符串拼接與表達式計算
HtmlTemplate html("{{ a+b+c+\"444\" }}\n" "{{x}} * {{y}} + 2 * 3 - 4 / {{x}} = {{ x*y+2*3-4/x }}\n", 1); JSONObject obj = OBJECT( KEYVALUE("a", "111"), KEYVALUE("b", "222"), KEYVALUE("c", "333"), KEYVALUE("x", 12), KEYVALUE("y", 34) ); cout << html.setValue(obj).render() << endl << endl; /*運行后輸出 111222333444 12 * 34 + 2 * 3 - 4 / 12 = 413.667 */
5. if-else-endif語句
HtmlTemplate html("{% if 1==1 %} 1==1 成立 {% else %} 1==1不成立 {%endif %}\n" "{% if !x %} x為空 {% else %} x不為空 {%endif %}\n" "{% if x==2 %} x==2 成立 {% endif %}\n" "{% if x+1!=2 %} x+1!=2 成立 {% endif %}\n" "{% if x<3 %} x<3 成立 {% endif %}\n" "{% if x>1 %} x>1 成立 {% endif %}\n" "{% if str==\"abcd\" %} str為abcd {% endif %}\n" "{% if 1 %} 常量表達式1 {% endif %}\n" "{% if 0 %} 常量表達式0,此處不會輸出 {%endif%}", 1); JSONObject obj = { {"x", 2}, {"str", "abcd"} }; cout << html.setValue(obj).render() << endl; /*運行后輸出 1==1 成立 x不為空 x==2 成立 x+1!=2 成立 x<3 成立 x>1 成立 str為abcd 常量表達式1 */
6.for與if嵌套使用
HtmlTemplate html("{%for x in list%}" "{%if x %}" "{% for y in list2%}" "{{x}} * {{y}} = {{ x*y }}\n" "{% endfor %}" "{% else %}" "x的值為空\n" "{%endif%}" "{% endfor%}", 1); JSONObject obj = OBJECT( KEYVALUE("list", LIST(1,2,3,4,5)), KEYVALUE("list2", LIST(1,2,3)), ); cout << html.setValue(obj).render() << endl << endl; /*運行后輸出 1 * 1 = 1 1 * 2 = 2 1 * 3 = 3 2 * 1 = 2 2 * 2 = 4 2 * 3 = 6 3 * 1 = 3 3 * 2 = 6 3 * 3 = 9 4 * 1 = 4 4 * 2 = 8 4 * 3 = 12 5 * 1 = 5 5 * 2 = 10 5 * 3 = 15 */
7.模版文件作為輸出
HtmlTemplate html("tmpl.html"); JSONObject context = OBJECT( ... ); FILE* f = fopen("output.html", "w"); // 寫入到文件中 string&& str = html.setValue(context).render(); fwrite(str.c_str(), 1, str.size(), f); fclose(f); /*運行后,代開當前目錄的tmpl.html文件作為輸入,輸出文件為output.html*/ /*如果tmpl.html不存在則拋出異常*/
8. 異常處理
HtmlTemplate html("{% if 1 %} xxx ", 1); // 不傳入context try { cout << html.render() << endl; } catch(exception& e) { cerr << e.what() << endl; } cout << endl;
運行后終端上打印如下,
會提示異常的類名,異常文件所在位置,代碼行數,以及一些錯誤的信息。
討論
1. 實現一個簡單的表達式計算器用什么方法比較好?(例如 {{ 2.3*3+4/5*x }} 這類表達式)
我分享一下我自己的方法,有什么更好的方法一起討論一下。
double cJinja::HtmlTemplate::calculator(vector<any>& number, vector<char>& op) { // 例如下表達式會成為 // 1 - 2 - 3 + 2 *3 * 4 - 4*5 // vector<char> op = { '-', '-', '+', '*', '*', '-', '*' }; // vector<any> number = { 1, 2, 3, 2, 3, 4, 4, 5 }; if (number.size() != op.size() + 1) throwException(TemplateParseException, "運算符號數和操作數不匹配"); /* 定義計算器的內部函數 */ auto calc = [](any& var1, double var2, char op) -> double{ // var2 + var1 // var2 * var1 // var2 - var1 // var2 / var1 // 注意順序 #define CALC(op2) \ if(#op2[0] == op) { \ if (var1.type() == typeid(int)) \ return var2 op2 static_cast<double>(any_cast<int>(var1)); \ else if (var1.type() == typeid(float)) \ return var2 op2 static_cast<double>(any_cast<float>(var1)) ; \ else if (var1.type() == typeid(double)) \ return var2 op2 static_cast<double>(any_cast<double>(var1)) ; \ } CALC(+); CALC(-); CALC(*); CALC(/); throwException(TemplateParseException, "不允許對空指針進行運算"); #undef CALC }; vector<double> num_stack; // 計算中間結果存儲棧 num_stack.push_back(calc(number[0], 0, '+')); // 獲取值 number[i+1] + 0 (加法運算零元為0,乘法運算零元為1) /* 計算 * / 法*/ for (size_t i = 0; i < op.size(); i++) { if (op[i] == '+' || op[i] == '-') { num_stack.push_back(calc(number[i + 1], 0, '+')); // number[i+1] + 0 } else if (op[i] == '*' || op[i] == '/') { double var1 = num_stack.back(); num_stack.pop_back(); num_stack.push_back(calc(number[i + 1], var1, op[i])); // var1/number[i+1] 或者是 var1/number[i+1] } else throwException(TemplateParseException, str_format("非法操作符 %d", op[i])); } /* 計算 + - 法*/ double result = num_stack[0]; size_t i = 1; for (auto& ch : op) { if (ch == '+') { result += num_stack[i++]; } else if(ch == '-') { result -= num_stack[i++]; } } return result; }
2. 拋出異常包含更多的信息
我定義了一個throwException宏,如下
#define throwException(Exception, ...) { \ std::cerr << "[" << #Exception << "] : FILE: " << string(__FILE__).substr(string(__FILE__).find_last_of('/') + 1) << " LINE: " << __LINE__ << " FUNCTION: " <<__FUNCTION__ << std::endl; \ throw Exception(__VA_ARGS__); \ }
其中__FILE__ 為文件名,__LINE__ 為當前代碼行數,這些都是C中的內置宏,__VA_ARGS__是可變參數,對應于宏函數參數中的....
覺下一個階段學習的重點會是 spark rdd + scala 相關的編程(spark sql + scala)。
這章節原書內容比較簡潔,還是要有一定的功底才能看懂。
---------------------------------
開發性能調優
關于Spark 開發調優及Hive SQL腳本調優的書籍和博客已經有很多了,本章將側重講解在開發畫像過程中可能遇到的一些共性問題,及對應的解決方案。
數據傾斜調優
數據傾斜是開發畫像過程中常遇到的問題,當任務執行一直卡在map 100%、reduce 99%,最后的1% 花了幾個小時都沒執行完時,這時一般是遇到了數據傾斜。
問題出現的原因是當進行分布式計算時,由于某些節點需要計算的數據較多,導致其他節點的reduce階段任務執行完成時,該節點的任務還沒有執行完成,造成其他節點等待該節點執行完成的情況。
比如兩條大表在join的時候大部分key對應10條數據,但是個別幾個key 對應了100萬條數據,對應10條數據的task很快執行完成了,但對應了100萬數據的key則要執行幾個小時。
圖5-1 所示的是一個典型的例子。
圖5-1 數據傾斜場景
bb這個key在3個節點上有11條數據,aa 和 cc在3個節點上分別由2條和1條數據,這些數據都會被拉取到task上處理。處理bb 這個task 的運行時間可能是處理aa和 cc的task的運行時間數倍,整體運行速度由最慢的task決定。
下面介紹兩種解決數據傾斜問題的方案。
方案一:過濾掉傾斜數據
當少量key重復次數特別多,如果這種key 不是業務需要的key,可以直接過濾掉。這里有一張埋點日志表ods.page_event_log,需要和訂單表dw.order_info_fact做join關聯。
在執行Hive的過程中發現任務卡在map 100%、reduce 99%,最后的1% 一直運行不完??紤]應該是在join的過程中出現了數據傾斜,下面進行排查。
對于 ods.page_event_log 表查看出現次數最多的key:
將key 按出現次數從多到少排序(下圖所示)
圖 5-2 日志表key按出現次數倒排序
同樣地,對訂單表dw.order_info_fact 查看出現次數最多的key:
日志表key 按出現次數倒排序,下圖(5-3)所示
5-3 訂單表key 按出現次數倒排序
從上面的例子可以看出,日志表和訂單表通過cookieid進行join,當cookieid為0的時候,join操作將會產生142286*142286條數據,數據量如此龐大的節點系統無法處理過來。
同樣當cookieid 為null 值和空值時也會出現這種情況,而且cookieid為這三個值時并沒有實際的業務意義。因此在對兩個表做關聯時,排除掉這3個值以后,就可以很快的計算出結果了。
--------------------------------------
*請認真填寫需求信息,我們會在24小時內與您取得聯系。