第四章 建議學習時間2小時 課程共10章node
學習方式:詳細閱讀,並手動實現相關代碼mysql
學習目標:此教程將教會你們 安裝Node、搭建服務器、express、mysql、mongodb、編寫後臺業務邏輯、編寫接口,最後完成一個完整的項目後臺,預計共10天課程。web
node.js事件機制sql
node.js是單線程,可是經過事件和回調支持併發,能夠實現很是高的性能。mongodb
node.js全部的API都是經過異步調用。第一堂課的時候,咱們寫過一個同步和異步的示例(以下),當初說到:同步代碼先執行完成,而後才執行異步代碼。express
setTimeout(function(){ console.log(1000000000); },0); for(var i=0; i<1000; i++){ console.log(i); }
而對於異步的多個代碼,它們的執行順序是怎樣的呢?試試下面的代碼:服務器
今天的代碼咱們放到一個新的文件夾 中,爲了完成下面的文件讀取,咱們須要提早準備一個a.txt的文件(注意:文件格式最好是uft-8)併發
main.js中寫入以下代碼:異步
var fs = require("fs"); //node 內置模塊可直接引入 fs:文件系統操做模塊 fs.readFile("./a.txt","utf-8",function(err,data){ //讀取文件 if(err) throw err; console.log(data); }); setTimeout(function(){ console.log("定時器打印!"); },0);
使用 node 運行 main.js後,你會發現定時器的先打印,(增長定時器的觸發時間,你會發現,打印的順序會改變。)函數
具體的異步代碼執行順序,是由node.js內部機制控制的,咱們很難準確預知。這裏給你們介紹一下node.js的事件模型:
Node.js 使用事件驅動模型,當web server接收到請求,就把它關閉而後進行處理,而後去服務下一個web請求。
當這個請求完成,它被放回處理隊列,當到達隊列開頭,這個結果被返回給用戶。
這個模型很是高效可擴展性很是強,由於webserver一直接受請求而不等待任何讀寫操做。(這也被稱之爲非阻塞式IO或者事件驅動IO)
在事件驅動模型中,會生成一個主循環來監聽事件,當檢測到事件時觸發回調函數。
回調函數
回調函數就是將一個函數做爲另外一個函數的參數傳入,做爲另外一個函數內部執行的函數。
咱們上面示例中的文件讀取方法中,第三個參數是一個回調函數,當文件讀取完成,就會自動調用這個函數。
fs.readFile("./a.txt","utf-8",function(err,data){ //讀取文件 if(err) throw err; console.log(data); });
上面的回調是封裝好的,那麼咱們本身來寫一個回調函數的實現樣子:
建立 一個js文件,寫入以下代碼:
function fn01(data,callback){ if(data){ callback("",data); }else{ var err = new Error("錯誤了"); callback(err) } } fn01("aa",function(err,data){ if(err){ console.log("錯誤"+err); }else{ console.log(data); } })
上面代碼是回調函數的標準模型,咱們在調用 fn01的時候,傳入了兩個參數,第一個是字符串,第二個是一個回調函數,當參數傳入之後。咱們來看fn01的主方法,方法中檢測第一個參數的存在狀況來,而後執行callback方法,也就是執行了當參數傳入的那個方法。
異步IO操做
咱們前面講的文件讀取的方式是一次性所有讀取,當文件過大的時候,一次性讀取不只緩慢,並且影響用戶體驗,那麼怎麼實現分步讀取呢,
這就得使用到異步IO的操做,像水流同樣流出一段取得一段。
具體實現:
咱們建立一個文件讀取流,先上代碼
var fs = require("fs"); var data = ""; //聲明一個空字符串來存讀取的數據 var rs = fs.createReadStream("a.txt"); rs.setEncoding("utf-8"); //監聽當有數據流入的時候 rs.on("data",function(chunc){ data += chunc; //將讀取的數據拼接到data上。 console.log("..."); //讀的過程當中,咱們打印三個點。 }); rs.on("end",function(){ console.log("沒有數據了") });
咱們將 a.txt中的內容增長,以讓讀取時間變長,
代碼中,建立main3.js寫入上面的代碼,使用 reateReadStream建立讀取流對象,在對象上使用on監聽「data」讀取數據的事件,每讀取一段數據,就會觸發這個事件,當讀取完畢, 就會觸發「end」事件。
執行main3.js,咱們就能夠看到下面打印的結果,從打印的多行"..."中,咱們就能夠看出,讀取了屢次纔讀完。
將讀取到的數據,慢慢的寫入 b.txt中
修改mai3.js中的代碼爲以下,增長了下面代碼的 4/10/16行,4行表示創建一個寫入流(若是寫入的文件不存在,會自動建立一個文件),10行表示往文件寫入東西,16行表示關閉寫入流。
1 var fs = require("fs"); 2 3 var rs = fs.createReadStream("a.txt"); 4 var ws = fs.createWriteStream("b.txt"); //寫入流 5 rs.setEncoding("utf-8"); 6 7 //監聽當有數據流入的時候 8 rs.on("data",function(chunc){ 9 console.log("..."); //讀的過程當中,咱們打印三個點。 10 ws.write(chunc,"utf-8"); //向文件寫入東西 11 }); 12 13 14 rs.on("end",function(){ 15 console.log("沒有數據了"); 16 ws.end(); //關閉寫入流 17 });
這樣咱們異步的讀取和寫入文件就實現了
好,今天就講這麼多,明天將講解:express 路由。