node.js不是一種獨立的語言,與php既是語言也是平臺不一樣,也不是JavaScript的框架,更不是瀏覽器的庫。node.js是一個讓JavaScript運行在服務端的開發平臺。php
JavaScript是由客戶端而產生,node.js爲網絡而生html
具備複雜邏輯的網站node
基於社交網站的大web的應用c++
web scoket服務器web
TCP/UDP套接字應用程序chrome
命令行工具npm
交互式終端程序編程
node.js最大的特性就是採用異步式I/O與事件驅動的架構設計。對於高併發的解決方案,傳統的架構是多線程模型,也就是爲每一個業務邏輯提供一個系統線程,經過系統線程切換來彌補同步式I/O調用時的事件開銷。node.js使用的單線程模型,在執行的過程當中會維護一個事件隊列,程序在執行時在進入時間循環等待下一個事件到來。json
普通:res = db.query("select * form user")數組
res.output();
node.js: res = db.query("select * form user",function(res){
res.output();
})
程序會自動往下執行
四、瀏覽器引擎革命
Google chrome的引擎是V8,node.js的引擎引用的就是V8,因此它快
五、部署node.js的環境
node.js官方,http://nodejs.org 下載安裝包,安裝後,打開cmd的的dos窗口,運行node
打開一個文本編輯器,其中輸入console.log("Hello World"),並保存爲test.js
打開dos窗口進入該文件的目錄運行 node test.js,執行則能夠看到輸出的Hello World
node -v 輸出版本號
node -e eval script eval("console.log('哈哈')") 例:node -e "console.log('哈哈')";直接執行
node 直接進入編譯模式 console.log("111") 第一行是輸出,第二行是返回值
創建一個app.js
1 var http = require("http"); 2 http.createServer(function(req,res){ 3 res.writeHead(200,{'Content-Type':'text/html'}); 4 res.write('<h1>Node.js</h1>'); 5 res.end('<p>PCAT</p>'); 6 }).listen(3000); 7 console.log('HTTP server is listening at port 3000');
接下來,node app.js 打開瀏覽器訪問http://localhost:3000便可,這樣就部署了一個web
npm install supervisor -g(在nodejs\node_modules\npm目錄下)安裝supervisor來控制調試代碼,不須要每次中止重啓node.js的服務
使用supervisor app.js啓動
node.js最大的特性就是異步式I/O與事件緊密結合的編程模式。這種模式與傳統的同步式IO線性的編程思路有很大的不一樣,由於控制流很大程度上要靠事件和回調函數來組織,一個邏輯要拆分爲若干個單元格
線程在執行中若是遇到磁盤讀寫或網絡通訊,一般要耗費較長時間。這時操做系統會剝奪這個線程的CPU控制權,使其暫停執行,同時把資源讓給其餘的工做線程這種線程調度方式稱爲阻塞,當I/O操做完畢時,操做系統將這個線程的阻塞狀態解除,回覆其對CPU的控制權,令其繼續執行
針對全部I/O操做不採用阻塞策略,當線程遇到I/O操做時,不會以阻塞的方式等待I/O操做的完成或數據的返回,二隻是將IO請求發送給操做系統,繼續執行下一條語句,當操做系統完成IO操做時,以事件的形式通知執行IO操做的線程,線程會在特定時候處理這個事件,爲了處理異步IO,線程必須有事件循環,不斷地檢查有沒有未處理的時間,依次予以處理
非阻塞模式下,一個線程永遠在執行計算操做,這個線程所使用的CPU核心利用率永遠是100%,IO以事件的方式通知
阻塞模式下,多線程每每能提升系統吞吐量,由於一個線程阻塞還有其餘線程在工做,多線程可讓CPU資源不被阻塞中的線程浪費
同步式IO(阻塞式)
利用多線程提供吞吐量
經過事件片分隔和線程調度利用多核CPU
須要由操做系統調度多線程使用多核CPU
難以充分利用CPU資源
內存軌跡大,數據局部性弱
符合線性的編程思惟
異步式IO(非阻塞)
單線程便可實現高吞吐量
經過功能劃分利用多核
能夠將但相處綁定到單核CPU
能夠充分利用CPU資源
內存軌跡小,數據局部性強
不符合傳統編程思惟
1 var fs = require("fs"); 2 var data = fs.readFile("file.txt","UTF-8",function(err,data){ 3 if(err){ 4 console.log("read file err"); 5 }else{ 6 console.log(data); 7 } 8 }) 9 console.log("end,");
結果:end
文件內容
1 var fs = require("fs"); 2 var data = fs.readFileSync("file.txt","UTF-8"); 3 console.log(data); 4 console.log("end");
結果:文件內容
end
調用時所作的工做只是將異步式IO請求發送給了操做系統,而後當即返回並執行後面的語句,執行完之後進入事件循環監聽事件,當fs接收到IO請求完成的事件時。事件循環會主動調用回調函數完成後續工做。同步則是阻塞等待文成後,繼續執行
//聲明事件對象 var EventEmitter = require("events").EventEmitter; var event = new EventEmitter(); //註冊事件 event.on("some_event",function(){ console.log(111); }) //觸發事件 setTimeout(function(){ event.emit("some_event"); },3000)
node.js在何時進入事件循環呢
node.js程序是由事件循環開始,到事件循環結束,全部的邏輯都是事件的回調函數
如何使用自定義事件呢?
事件的回調函數在執行過程當中,可能會發出IO請求或直接發射(emit)事件,執行完畢後再返回事件循環
概念:模塊和包是node.js最重要的支柱。開發一個具備必定規模的程序不願只用一個文件,一般須要把各個功能拆分、分裝、而後組合起來。模塊正是爲了實現這種方式而誕生,在瀏覽器JavaScript中,腳本模塊的拆分和組合一般使用html的script標籤來實現,node.js提供了require函數來調用其餘模塊,並且模塊都是基於文件,模塊和包的區別是透明的,常常不作區分
模塊和文件是一一對應的。一個node.js文件就是一個模塊,這個文件多是JavaScript代碼、json或者編譯過的c/c++擴展。
var http = require("http"),其中http是node.js的一個核心模塊,經過require函數獲取這個模塊,而後使用其中的對象
node.js提供了exports和require兩個對象,其中exports是模塊公開的接口,require用於從外部獲取一個模塊的接口,即獲取模塊的exports對象
module.js
1 var name; 2 exports.setName = function(theName){ 3 name = theName; 4 } 5 exports.sayHello = function(){ 6 console.log("hello"+name); 7 }
getModule.js
1 var myModule = require("./module"); 2 myModule.setName("wang er"); 3 myModule.sayHello();
上面的例子相似建立一個對象,但實際上和對象又有本質的區別,由於require不會重複加載模塊,不管調用多少次require,獲取的模塊都是同一個
getModule2.js
1 var myModule1 = require("./module"); 2 myModule1.setName("wang wu"); 3 var myModule2 = require("./module"); 4 myModule2.setName("hello world"); 5 myModule1.sayHello();
有時咱們想把一個對象封裝到模塊中
定義模塊:singleobject.js
1 function hello(){ 2 var name; 3 this.setName = function(theName){ 4 name = theName; 5 } 6 this.sayHello = function(){ 7 console.log("hello"+name); 8 } 9 }; 10 module.exports = hello;
引入模塊使用:getsingleobject.js
1 var hello = require("./singleobject"); 2 var he = new hello(); 3 he.setName("sugar"); 4 he.sayHello(); 5 var he2 = new hello(); 6 he2.setName("txy"); 7 he2.sayHello();
exports自己僅僅是一個普通的空對象,即{},它是專門用來聲明接口
2.一、包的概念
包是在模塊基礎上更深一步的抽象,node.js的包相似於c/c++的函數庫或者Java的類庫,它將某個獨立的功能封裝起來,用於發佈、更新、依賴管理的版本控制。開發了npm來解決包的發佈和獲取需求。
2.二、如何建立一個包
commonJS規範的包具有如下特徵:
package.json必須在包的頂層目錄下
二進制文件應該在bin目錄下
JavaScript代碼應該在lib目錄下
文檔應該在doc目錄下
單元測試應該在test目錄下
Node.js對包要求沒有那麼嚴格,只要頂層目錄下有package.json,並符合基本規範便可
(1)做爲文件夾的模塊
somepackage文件夾(最簡單的包,就是做爲文件夾的模塊)
建立一個文件夾somepackage,裏面有一個index.js,裏面提供一個方法sayHello()
var somepackage = require("./somepackage");
somepackage.sayHello();
使用這種方法能夠把文件夾封裝成一個模塊,即包。包一般是一些模塊的集合,在模塊的基礎上提供了更高層的抽象,至關於提供了一些固定接口的函數庫,經過定製package.json,咱們能夠建立更符合規範的包進行發佈。
(2)package.json
在somepackage文件夾下,咱們建立一個package.json的文件,內容{"main":"./lib/index.js"}
node.js在調用某個包時,會檢查包中package.json文件的main字段,將其做爲包的接口模塊,若是package.json或main字段不存在,會尋找index.js或index.code做爲包的接口
package.json的規範屬性:
name:包的名稱,必須是惟一
description:包的簡要說明
version:符合語義化版本識別規範的版本字符串
keywords:關鍵字數據,一般用於搜索
maintainers:維護者數組,每一個元素要包含name、email、web可選字段
contributes:貢獻者數組,格式與maintainers相同。包的做者應該是貢獻者數據的第一個元素
bugs:提交bug的地址,能夠是網址或者是電子郵件地址
licenses:許可證數組,每一個元素要包含type、url字段
repositories:倉庫託管地址數組,每一個元素要包含type、url、和path、字段
dependencies:包的依賴,一個關聯數組,由包名稱和版本號組成