Node_模塊

簡介

V8引擎自己就是用於Chrome瀏覽器的JS解釋部分,可是Ryan Dahl,把V8搬到服務器,用於作服務器的軟件。
Node是一個專一於實現高性能Web服務器優化的專家,在遇到V8而誕生的項目html

  • 沒有歷史包袱,沒有同步I/O。不會出現一個同步I/O致使事件循環性能急劇下降的狀況。
  • V8性能足夠好,遠遠比Python,Ruby等其它腳本語言的引擎快。
  • JavaScript語言的閉包特性很是方便,比C中的回調函數好用。

Node可讓JavaScript運行在服務器端的平臺開發,它讓JavaScript的觸角延伸到了服務器端,能夠與PHP,JSP,Python,Ruby等語言實現後端開發。前端

但Node彷佛有點不一樣:node

  • Node不是一種獨立的語言,與PHP,JSP,Python,Perl,Ruby的「即便語言,也是平臺」不一樣,Node使用的是JavaScript進行編程,運行在JavaScript引擎上(V8)
  • 與PHP,JSP等相比(PHP,JSP,.net都須要運行在服務器程序上,Apache,Naginx,Tomcat,IIS),Node跳過了Apcahe,Naginx,IIS等HTTP服務器,它本身不用建設在任何服務器任何之上。Node的設計理念與經典架構(LAMP = Linux + Apache + MySQL + PHP) 有着很大的不一樣,能夠提供強大的伸縮能力。
  • Node沒有Web容器。
  • Node是花最小的硬件成本,追求更高的併發,更高的處理性能。

Node特色

所謂特色,就是Node若是解決服務器高性能瓶頸問題。
JavaScript有什麼特色的時候,會當即想到 單線程事件驅動面向對象。可是JavaScript精髓 以爲是 this閉包做用域鏈函數。才使得這門語言魅力無窮。mysql

單線程jquery

在Java,PHP,或者.net 等服務器端語言中,會爲每個用戶端鏈接建立一個新的線程。而每一個線程須要耗費大約2MB內存。理論上,一個8GB內存的服務器能夠同時鏈接的最大用戶數4000個左右。要讓Web應用程序支持更多的用戶,就須要增長服務器的數量,而Web應用程序的硬件成本就上升了。
Node不爲每一個用戶鏈接建立一個新的線程,而僅僅使用一個線程。當有用戶鏈接了,就觸發一個內部事件,並經過非阻塞I/O,事件驅動機制,讓Node程序宏觀上也是並行的。Node中,一個8GB內存的服務器,能夠同時處理超過4萬用戶的鏈接。
單線程好處:操做系統徹底再也不有線程建立,銷燬的時間開銷。
單線程壞處:就是一個用戶形成了線程的奔潰,整個服務都奔潰了,其它人的服務也就奔潰了。git

clipboard.png

clipboard.png

單線程也可以形成宏觀上的「併發」。github

非阻塞I/O redis

非阻塞I/O non-blocking I/O sql

例子:訪問數據庫取得數據的時候,須要一段時間。
在傳統的單線程處理機制中,在執行了訪問數據庫代碼以後,整個線程都將暫停下來,等待數據庫返回結果,才能執行後面的代碼。也就是說I/O阻塞了代碼的執行,極大下降了程序執行的效率mongodb

Node採用了非阻塞型I/O機制,所以在執行了訪問數據庫的代碼以後,將當即轉而執行後面的代碼,把數據庫返回的結果的處理代碼放在回調函數中,從而提升了程序的執行效率。
當某個I/O執行完畢時,將以時間的形式通知執行I/O操做的線程,線程執行了這個事件的回調函數。爲了處理異步I/O,線程必須有事件循環,不斷的檢查是否有未處理的時間。依次予以處理。
阻塞模式下,一個線程只能處理一項任務,要想提升吞吐量必須經過多線程。而非阻塞模式下,一個線程永遠在執行計算操做,這個線程的CPU核心利用率永遠是100%。 有一種相似 : 與其多人工做,可是好多人閒着,倒不如一我的工做,往死裏幹活。

clipboard.png

事件驅動
事件驅動 event-driven

在Node中,客戶端請求創建鏈接,提交數據等行爲,會觸發相應的時間。在Node中,在一個ie時時刻,只能執行一個事件回調函數,可是在執行一個事件回調函數的中途,能夠轉而處理其它事件(好比:有新用戶鏈接),而後返回繼續執行原事件的回調函數。這種處理機制,稱爲:"事件環"機制。

Node底層是C++(V8也是C++) 編寫。底層代碼中,近半數都用戶事件隊列,回調函數隊列的構建。用事件驅動來完成服務器的任務調度。用一個線程,擔負起了處理很是多的任務。

clipboard.png

單線程,減小內存開銷,操做系統的內存換頁。
如某一個任務,執行了,可是被I/O阻塞了,因此這個縣城就阻塞了。非阻塞I/O,不會傻等I/O語句結束,而會執行後面的語句。利用事件驅動,不論是新用戶的請求,仍是老用戶的I/O完成,都將以事件方式加入事件環中,等待調度。

Node全部的I/O都是異步的,回調函數嵌套回調函數。

Node是單進程單線程應用程序,可是經過事件和回調支持併發,因此性能很是高。
Node的每一個API都是異步的,並做爲一個獨立線程運行,使用異步函數調用,並處理併發。
Node基本上全部的事件機制都是用設計模式中的觀察者模式實現的。
Node單線程相似進入一個while(true)的事件循環,直到沒有事件觀察者退出,每一個異步事件都生成一個事件觀察者,若是有事件發生就調用該回調函數。

模塊

moduel

Node中,以模塊爲單位劃分全部功能,而且提供一個完整的模塊加載機制,能夠將應用程序話費爲各個不一樣的部分。

Node中,一個JavaScript文件中定義的變量,函數,都只在這個文件內部有效果。

俠義的說,每個JavaScript文件都是一個模塊,而多個JavaScript文件之間能夠相互require,共同實現一個功能,總體外對,又稱之爲廣義上的模塊

好處:

  • 減小重複代碼量,增長可讀性。
  • 方便進行代碼規劃。
  • 方面使用第三方模塊。

當須要從JS文件外部引用到這些變量,函數時,必須使用exprots對象,或者module.exprots進行暴露。使用者須要使用require(); 函數引入這個JS文件。

function People( name,sex,age ){
    this.name = name;
    this.sex = sex;
    this.age = age;
}

People.prototype = {
    sayHello: function(){
        console.log(this.name+this.sex+this.age);
    }
};

// 暴露
module.exports = People;

// 使用
var People = require('./People.js');

var p1 = new People('zf','nv','23');

p1.sayHello();

一個JavaScript文件,能夠向外exprots無數個變量,函數,對象,可是require(); 的時候,僅僅須要 載入一次JS文件便可。 因此,無形以後,會增長一個頂層命名空間。

// 變量
// 須要變量引用 使用  
exports.a = 10;
// 直接須要變量值使用.
module.exports = name;



// 對象
module.exports = {
  name1: 123,
  name2: 456
}
// 暴露結果: { name1: 123, name2: 456 }

exports.msg = {
  name1: 1,
  name2: 2
}
// 暴露結果 : { msg: { name1: 1, name2: 2 } }



// 函數
exports.showMsg = function () {
}

// 暴露結果 : { showMsg: [Function] }
// 在 引用結果 須要  經過  變量 引用對象 執行
// var msg = require();
// msg.showMsg();


module.exports = function () {
}
// 暴露結果 [Function]
// 引入文件的 變量  直接執行

模板引擎

數據綁定,成爲一個完整的HTML字符串。
Node中使用的模板:ejs 和 jade

後臺模板引擎:

<ul>
    <% for(var i = 0 ; i < news.length ; i++){ %>
      <li><%= news[i] %></li>
    <% } %>
</ul>

// 模板中須要的數據
var dictionary = {
  a:6,
  news : ["xixi","haha"]
};

HTTP模塊

主要類

Class: http.Server
var server = http.createServer();

server就是http.Server類的實例。

經常使用的方法有:

server.listen(port, [hostname], [backlog], [callback])
Class: http.ServerResponse
var server = http.createServer(function(req,res){  });

res就是 http.ServerResponse類的實例。

Class: http.IncomingMessage

``
var server = http.createServer(function(req,res){ });
``
req就是http.IncomingMessage類的實例。

server對象

可使用on語法監聽某個事件。

var http = require('http');
var server = http.createServer();

server.on('request',function ( req,res ) {
  res.setHeader('Content-type','text/html;charset=utf8');
  if ( req.url == '/' ){
    res.end('index');
  } else {
    res.end('404');
  }
});

server.listen(8080,'localhost');

req對象

每次上行請求頭對象

req.headers //HTTP上行請求頭

clipboard.png

req.httpVersion  //  http請求的版本。如今基本上都是1.1   
req.method    //    「GET」、」POST」就是請求的類型   
req.url // 用戶請求的網址

res對象

每次下行響應對象

res.end()  // 每次都要有這個語句,表示此次的發送已經結束
    // 參數必須是string、buffer(圖片、文件)。

res.write()    // 就是寫HTTP下行請求的body

res.setHeader()          // 設置返回的報文頭部

res.statusCode = 404;   // 設置狀態碼

res.writeHead()          // 和res.setHeader差很少
res.writeHead(288 , {"Content-Type":"text/plain"});

url模塊

做用內置模塊,解析url,解析地址。 分析和解析 URL 的工具

url.parse()

url.parse()就是用來解析網址,接收一個字符串,返回一個JSON:

var obj = url.parse("http://localhost:8080/a/b/c/1.html?name=ting&age=21");

clipboard.png

url.parse方法第二個參數若是是true,那麼返回的對象中的query就是json

query: { xingming: 'xiaoming', age: '12' }

querystring模塊

querystring模塊是專門用來解析GET請求的查詢字符串的。

console.log( qs.parse('name=ting&age=21&hobby=run&hobby=sing') );
// 返回:{ name: 'ting', age: '21', hobby: [ 'run', 'sing' ] }

path模塊

處理和轉換文件路徑的工具集,專門處理路徑

path.basename()   返回路徑中的文件名
path.dirname()   返回路徑中的文件夾名
path.extname()   返回路徑的拓展名

console.log( path.basename('/xixi/haha/a.html') );  //a.html
console.log( path.extname('/xixi/haha/a.html') );  //.html
console.log( path.dirname('/xixi/haha/a.html') );  ///xixi/haha

fs模塊

文件處理模塊,能夠讀文件,也能夠寫文件

fs.readFile();            //讀取文件內容   
fs.readDir();            //讀取文件夾名
fs.appendFile();        //追加文件
fs.writeFile();         //寫入文件(覆蓋原有的)
fs.rename();            //修改文件名

自定義模塊

每個js文件中能夠當作是一個小小的模塊
require()誰,就會執行誰。就至關於調用一個函數。A require B, 先執行B所有語句,而後執行A的剩餘語句。

require('./test/a.js');

每一個js文件就是一個閉包,聲明的函數、變量只在這個js文件內部有定義。
A require了 B , 那麼B裏面的全部路徑都要按照A的路徑寫。

若是須要使用到其它文件中的變量,使用exports暴露出去。

exports.*** = ***;
testA .js
var a = 100;
exports.a = a;

主文件

var testA  = requrie('./testA.js');    
console.log( testA.a );

暴露惟一的接口,module.exports ,通常使用到構造函數。

若是隻有寫文件載入,會去默認文件夾下:node_modules 尋找是否有當前須要載入的文件

require('test.js');

也能夠直接省略路徑、省略文件名,只寫文件夾名

require('aa');

實際上引用的是node_moduels文件夾裏面的aa文件夾裏面的index.js文件。
通常第三方模塊,都放入node_modules文件夾中。

package.json

配置信息:

{
  "name": "my_package",   //項目名字
  "version": "1.0.0",    //版本號
  "main": "index.js",   //入口文件
  "keywords": [],       //關鍵詞,就是搜索什麼npm上可以顯示你
  "author": "ag_dubs",   //做者
  "license": "ISC",      //版權協議
  "repository": {             //代碼託管倉庫,這個會自動生成一個鏈接
    "type": "git",
    "url": "https://github.com/ashleygwilliams/my_package.git"
  },
  "bugs": {               //若是發現bug應該交給誰
    "url": "https://github.com/ashleygwilliams/my_package/issues"
  },
    "dependencies": {
    "underscore": "*",
  "date-format" : "0.0.2"
  },
    "homepage": "https://github.com/ashleygwilliams/my_package"   //我的網站
}

最重要的信息是:依賴

{
  "dependencies": { 
    "underscore": "*",
  "date-format" : "^0.0.2"
  }
}

formidable

處理POST請求

// formidable 語法
var form = new formidable.IncomingForm();

// 設置上傳路徑
form.uploadDir = "./uploads";
form.parse(req, function(err, fields, files) {
  // fields是普通域,就是普通的文本框、單選按鈕、複選按鈕、textarea都存在這個對象裏面
  // files是上傳的文件信息
  var newname = df('yyyyMMddhhmmssSSS', new Date());
  
  fs.rename(files.touxiang.path , "./uploads/" + newname + ".jpg",function(err){
      if(err){
          res.end("error");
          return ;
      }
  });
  res.end("ok");
});

爬蟲初級

須要的npm包:

  1. express
  2. request (後端發送請求的模塊)
  3. cheerio (像前端同樣操做拉取回來的數據)

爬蟲以及Robots協議介紹:

  1. 爬蟲,是中自動獲取網頁內容的程序。是搜索引擎的重要組成部分,所以搜索引擎優化很大程度上就是針對爬蟲而作出的優化。
  2. robots.txt是一個文本文件,robots.txt是一個協議,不是一個命令。robots.txt是爬蟲要查看的第一個文件。robots.txt文件告訴爬蟲在服務器上什麼文件是能夠被查看的,搜索機器人就會按照該文件中的內容來肯定訪問的範圍。

clipboard.png

var express = require('express');
var app = express();
var cheerio  = require('cheerio');

app.get('/', function(req, res){

    var request = require('request');

    request('https://linxingzhang.com', function(err, response, body) {
        if (!err && response.statusCode == 200) {
            $ = cheerio.load(body); // 和jquery的$('body') 同樣

            res.json({
                panel: $('#link-panel li').length
            });
        }
    });

});

app.listen(3000);

使用supervisor啓動

> supervisor start app.js

經常使用npm包

模塊名 連接地址 簡介
async async 異步操做管理
bl bl 二進制數據解析
bluebird bluebird 異步操做管理
browserify browserify 發佈瀏覽器可用的包
bunyan bunyan 日誌(logging)管理
chai chai 斷言
chalk chalk 命令行彩色輸出
co co 異步流程管理
colors colors 命令行彩色輸出
commander commander 命令行工具
debug debug Debug輸出器
dockerode dockerode Docker管理
duplexify duplexify Stream流操做工具
event-stream event-stream Stream流操做工具
express express Server服務器框架
hapi hapi Server服務器框架
koa koa Server服務器框架
glob glob 文件名匹配
grunt grunt 構建工具
gulp gulp 構建工具
hyperquest hyperquest 輕量級HTTP客戶端
istanbul istanbul 測試用例覆蓋率分析
JSONStream JSONStream Stream流管理工具
levelup levelup LevelDB
lodash lodash 函數式編程工具
log4js log4js 日誌(logging)管理工具
minimatch minimatch 文件名匹配
minimist minimist 命令行操做
mocha mocha 單元測試
moment moment 日期時間輸出
mongodb mongodb MongoDB
mysql mysql MySQL
nconf nconf 配置工具
needle needle 輕量級HTTP客戶端
node-fetch node-fetch Fetch API
nodemailer nodemailer Email客戶端
passport passport 登陸和認證
pg pg Postgres
pump pump Stream流管理工具
redis redis Redis
request request HTTP客戶端
restify restify REST API搭建
socket.io socket.io WebSocket實時通訊
split2 split2 Stream流管理工具
tape tape 單元測試
through2 through2 Stream流管理工具
underscore underscore 函數式編程工具
ws ws Websockets
xml2js xml2js XML轉換爲JavaScript
http-server http-server 命令行的HTTP服務器
nrm nrm 更改NPM下載源
node-inspector node-inspector Node調試
supervisor supervisor 檢測Node進程的服務
nodemon nodemon 在文件有變化以後會自動重啓服務
相關文章
相關標籤/搜索