brook
brook是一個針對大規模web開發的Javascript框架,而不是一個工具集。
brook引用瞭UNIX下的pipe概念,輕松把所有的處理都串聯起來以共同完成任務。前一個處理的輸出作為後一個處理的輸入來完成參數的傳遞。通過brook你可以以MVC的方式來寫你的javascript程序。
http://hirokidaichi.github.com/brook/
brook框架使用namespace庫用於模塊的組織。
這裡再次用例子說明一下namespace的使用方法:
1 // 定義一個sample命名空間 2 Namespace('sample') 3 // 使用brook 4 .use('brook *') 5 .use('brook.util *') 6 .define( function (ns) { 7 var foo = function() { 8 alert('this is sample.foo'); 9 }; 10 11 // 定義對外公開的函數 12 // 外部模塊隻要use瞭sample之後,就可以通過ns.sample.foo()來調用 13 ns.provide({ 14 foo : foo 15 }); 16 }); 17 18 // 使用的例子 19 Namespace.use('sample').apply(function(ns) { 20 ns.sample.foo(); 21 });
要想理解brook框架,需要理解brook的幾個核心概念。
promise
簡單來說,promise就是封裝過的函數,它就是負責把值傳給下一個promise。就好比接力賽時候,把接力棒(value)傳給下一個成員(promise)。這樣就可以可以讓非同步的處理能夠按照類似同步處理的順序來編程。
1 var p = ns.promise(function(next, value){ 2 // 在這裡對value進行處理 3 // value是之前的promise傳遞進來的 4 5 // 把工作移交給下一個promise 6 next("new_value"); 7 });
那我們來看看promise能做什麼。比如有這樣的要求
1:等一秒
2:輸出moge
3:等兩秒
4:輸出muga
不用promise的時候:
1 (function() { 2 var firstInterval = setInterval(function() { 3 console.log("moge"); 4 clearInterval(firstInterval); 5 var secondInterval = setInterval(function() { 6 console.log("muga"); 7 clearInterval(secondInterval); 8 }, 2000); 9 }, 1000); 10 })();
這樣的代碼處理順序不好理解。如果改用promise的話:
1 Namespace("sample") 2 .use("brook *") 3 .use("brook.util *") 4 .define(function(ns) { 5 var p1 = ns.promise(function(next, value) { 6 console.log("moge"); 7 next("muga"); 8 }); 9 10 var p2 = ns.promise(function(next, value) { 11 console.log(value); 12 next(); 13 }); 14 15 ns.provide({ 16 execute: function() { 17 ns.wait(1000).bind(p1).bind(ns.wait(2000)).bind(p2).run(); 18 } 19 }); 20 }); 21 22 Namespace.use("sample").apply(function(ns) { 23 ns.sample.execute(); 24 });
其中bind函數可以接受多個參數,也可以寫成這樣:
ns.wait(1000).bind(p1, ns.wait(1000), p2).run();
promise的使用方法:
1:等待幾秒可以使用brook.util下的wait方法
2:promise之間“棒的交接”是通過bind方法實現的,也就是UNIX下的PIPE功能。
3:最後需要執行run()方法
channel
channel顧名思義就是頻道,管道的意思。在brook裡它表示promise的集合。可以把多個promise存放到一個channel裡,然後一起執行。
1 var p3 = ns.promise(function(next, value) { 2 console.log(value + "!"); 3 }); 4 5 var p4 = ns.promise(function(next, value) { 6 console.log(value + "!!"); 7 }); 8 9 ns.provide({ 10 execute: function() { 11 var channel = ns.channel("testChannel"); 12 channel.observe(p3); 13 channel.observe(p4); 14 ns.sendChannel("testChannel").run("hello"); 15 } 16 });
channel的使用方法:
1:observer:把promise追加到channel中
2:sendChannel:確定channel
3:最後通過run來執行channel裡所有promise
model
model是對channel進行包裝而成的。在model裡可以定義帶有名字的channel,這些channel都是一個個的method。
這個組件可以明確MVC中的M和V,即模塊和視圖。它可以寫出這樣的處理,model的method執行之後,它的結果傳到一個或者多個view(promise)。這就是觀察者模式。
var requestFilter = ns.promise(function(v){ v["viewer_id"] = viewer.getID(); retrun v; }); var create = ns.promise(function(n,v){ // get data n(response); }); var delete = ns.promise(function(n,v){ // get data n(response); }); var view1 = ns.promise(function(n,v){ // render html n(v); }); var view2 = ns.promise(function(n,v){ // render html n(v); }); var model = ns.createModel(); model.addMethod('create', ns.mapper(requestFilter).bind(create)); model.addMethod('delete', ns.mapper(requestFilter).bind(delete)); ns.from(model.method('create')).bind(view1).run(); ns.from(model.method('create')).bind(view2).run(); ns.promise().bind(model.notify('create').run({"body": "test"})); //向view1和view2傳遞參數{"body": "test"}
model的使用方法:
1:ns.createModel():生成model
2:model.addMethod():定義method名和相應的處理promise
3:ns.from():定義model的某個method執行完之後的處理
4:model.notify():執行model的method
widget
widget負責把html和命名空間的模塊關聯起來。看一個簡單的例子。
首先定義一個sample.widget的namespace。
1 // sample-widget.js 2 Namespace("sample.widget") 3 .use("brook.widget *") 4 .define(function(ns) { 5 ns.provide({ 6 registerElement: function(element) { 7 element.innerHTML = "Hello World!"; 8 } 9 }); 10 });
下面就是關於sample.widget的html頁面。
1 <html> 2 <head> 3 <title>widget sample</title> 4 <script type="text/javascript" src="js/namespace.js"></script> 5 <script type="text/javascript" src="js/brook.js"></script> 6 <script type="text/javascript" src="js/sample-widget.js"></script> 7 </head> 8 <body> 9 <h1>widget</h1> 10 <p class="widget" data-widget-namespace="sample.widget">hoge</p> 11 <p class="widget" data-widget-namespace="sample.widget">foo</p> 12 <p class="widget" data-widget-namespace="sample.widget">bar</p> 13 <script type="text/javascript"> 14 //entry point 15 Namespace.use("brook.widget *").apply(function(ns) { 16 ns.bindAllWidget.run(); 17 }); 18 </script> 19 </body> 20 </html>
這段代碼會把data-widget-namespace指定為sample.widget的p內容全部置換成hello world!
run()和subscribe()的區別
promise執行的時候需要使用run()方法。一個promise鏈處理完之後需要執行回調函數的時候不使用run,使用subscribe。
1 ns.promise().bind(function(next, value) { 2 next(value); 3 }).subscribe(function(value) { 4 console.log(value, "world!"); 5 }, "hello"); 6 //hello world! 7 8 9 ns.promise().bind(function(next, value) { 10 console.log(value); 11 next("no next"); 12 }).run("hello"); 13 //hello
brook.util
這個模塊裡面定義很多有用的方法。
mapper:定義裝飾處理
1 var input = ns.promise(function(next, value) { 2 next("this is input"); 3 }); 4 5 var mapper = ns.mapper(function(value) { 6 return value + "!"; 7 }); 8 9 var output = ns.promise(function(next, value) { 10 console.log(value); 11 next(value); 12 }); 13 14 //執行 15 input.bind(mapper).bind(output).run(); 16 //this is input!
filter:過濾器
1 var input = ns.promise(function(next, value) { 2 next(2); 3 }); 4 5 var evenFilter = ns.filter(function(value) { 6 return (value % 2) === 0; 7 }); 8 9 var output = ns.promise(function(next, value) { 10 console.log(value + " is even"); 11 next(value); 12 }); 13 14 //執行 15 input.bind(evenFilter).bind(output).run(); 16 //2 is even
scatter:分散器,value裡面的值依次調用下一個promise
1 var output = ns.promise(function(next, value) { 2 console.log(value); 3 next(value); 4 }); 5 6 //執行 7 ns.scatter().bind(output).run([1, 2, 3, 4, 5, 6]); 8 //1 9 //2 10 //3 11 //4 12 //5 13 //6
takeBy:從value裡面一次取n個調用下一個promise
1 var output = ns.promise(function(next, value) { 2 console.log(value); 3 next(value); 4 }); 5 6 //実行 7 ns.scatter().bind(ns.takeBy(2)).bind(output).run([1, 2, 3, 4, 5, 6]); 8 //[1, 2] 9 //[3, 4] 10 //[5, 6]
wait:等待n毫秒
cond:有條件執行promise,第一個參數是過濾器,第二個參數是promise。第一個參數為true的時候執行第二個參數的promise。
1 var output = ns.promise(function(next, value) { 2 console.log(value); 3 next(value); 4 }); 5 6 var isEven = function(num) { 7 return (num % 2 === 0); 8 }; 9 10 var done = ns.promise(function(next, value) { 11 console.log("done"); 12 }); 13 14 //実行 15 ns.cond(isEven, output).bind(done).run(2); 16 //2 17 //done 18 19 20 ns.cond(isEven, output).bind(done).run(3); 21 //done
match:根據value的值來決定執行哪一個promise。
1 var dispatchTable = { 2 "__default__": ns.promise(function(next, value) { 3 console.log("default"); 4 }), 5 6 "hello": ns.promise(function(next, value) { 7 console.log("hello"); 8 }), 9 10 "world": ns.promise(function(next, value) { 11 console.log("world"); 12 }) 13 }; 14 15 16 ns.match(dispatchTable).run("hello"); 17 ns.match(dispatchTable).run("world"); 18 ns.match(dispatchTable).run("hoge");
from:為promise鏈傳遞初始參數,也可以用run來傳遞。
1 ns.from("hello").bind(ns.debug()).run(); 2 //debug: hello
最後還可以通過github首頁的例子來體會,brook是怎麼實現MVC模式的
摘自:foxracle