Nodejs初識

呦_安徒生發表於2019-04-01

what it is?

  • Node.js的本質是一個Javascript的解析器
  • Node.js是Javascript 的執行環境
  • Node.js是一個伺服器程式
  • Node.js本身使用的是V8引擎
  • Node不是web伺服器

Why use it?

  • 為了提供高效能的web服務
  • IO效能強大
  • 事件處理機制完善
  • 天然能夠處理DOM
  • 社群非常活躍,生態圈日趨完善

The advantage

  • 處理大流量資料
  • 適合實時互動的應用
  • 完美支援物件資料庫
  • 非同步處理大量併發連結

官網地址

中文網地址

安裝cnpm

  • npm install cnpm 安裝cnpm

第一個node程式

  • 建立 hello.js 並編輯 console.log("helloworld")
  • node hello.js //執行

#node最簡單的web服務

  • 建立 server.js

  • 引入 原生 api

var http = require('htttp');
複製程式碼
  • 建立一個服務
http.createServer(function (request,response) {
    //定義HTTP頭
    response.writeHead(200, {'Content-Type':'text/plan'});
    
    //傳送相應的資料
    response.end('Hello world!\n');
}).listen(8000);

//服務執行之後輸出一行資訊
console.log('server is running...');
複製程式碼
  • 執行
node server.js
複製程式碼
  • 開啟瀏覽器 127.0.0.1:8000

Nodejs 環境及npm命令的深入

REPL

全稱互動式直譯器 敲 node 命令進入 可以在環境之後 直接進行程式碼 的編寫 運算 優點類似 瀏覽器的 console控制檯 一般來說我們可以在此環境下 進行一些 簡單的 程式碼運算 驗證

  • ctrl + c -退出當前終端
  • ctrl + c -按下兩次 退出 Node REPL
  • ctrl + d -退出Node REPL (linux環境下)
  • 向上/向下 鍵 -檢視輸入的歷史命令
  • tab鍵 -列出當前命令
  • .help -列出使用命令
  • .break -退出多行表示式
  • .clear -退出多行表示式
  • .save filename -儲存當前的Node REPL 會話到指定檔案
  • .load filename -載入當前 Node REPL 會話的檔案內容。

npm包管理器

  • npm install npm -g //升級npm
  • npm install express -g//安裝包express
  • npm uninstall packagename // 解除安裝包
  • npm search packagename // 查詢包
  • npm help
  • npm help install // 具體檢視 某個命令
  • cnpm 與 npm 的使用方法本質是相同的 只是伺服器不同 一個國內 一個國外

什麼是回撥

  • 函式呼叫方式分為三類 :同步呼叫、回撥和非同步呼叫。
  • 回撥時一種雙向呼叫模式
  • 可以通過回撥函式來實現回撥

阻塞與非阻塞

  • 阻塞和非阻塞關注的是程式在等待呼叫的結果(訊息,返回值)時的狀態。
  • 阻塞就是做不完不準回來
  • 非阻塞就是你先做,我現在看看有其他事沒有,做完了告訴我一聲
//阻塞時程式碼

var fs = require('fs');  

var data = fs.readFileSync('data.txt');   //  阻塞時用 同步讀取 readFileSync  非阻塞時用  readFile

console,log(data.toString());
複製程式碼
//非阻塞程式碼

var fs = require('fs');

fs.readFile('filename.txt',function(err,data){
    // todo something
    if(err){
        return console.error(err)
    }
    console.log(data.toString());
})
cosnole.log("程式執行完畢")
複製程式碼

Node.js事件驅動機制

事件驅動模型

事件與事件繫結

  • nodejs 是一個單程式 單執行緒的程式,它並不能同時併發完成更多的事情,只能通過事件或者回撥來實現併發效果
  • nodejs 的 api 全都是非同步執行的,而且都是作為獨立的執行緒處理的
  • nodejs 中的 幾乎所有的事件 都是依據觀察者模式 來實現的 觀察者模式 是設計模式中的一種
  • EventEmitters 物件 產生 Events 例項

事件處理程式碼

//1. 引入 events物件,建立 eventEmitter物件
var events = require('events');
var eventEmitter = new events.EventEmmitter();

//2. 繫結事件處理程式
var connctHandler = function  connected(){
    console.log('connected被呼叫了');
};
eventEmitter.on('connection', connctHandler()); //完成事件繫結
//3.觸發事件
eventEmitter.emit('connection');

console.log("程式執行完畢");
複製程式碼

Nodejs 模組化

模組化的概念和意義

  • 為了讓Node.js的檔案可以相互呼叫,Node.js提供了一個簡單的模組系統
  • 模組是Node.js應用程式的基本組成部分
  • 檔案和模組是一一對應的。一個Node.js檔案就是一個模組
  • 這個檔案可能是Javascript程式碼、JSON或者編譯過的C/C++擴充套件
  • Node.js中存在4類模組(原生模組和3種檔案模組)

Node.js中的模組

Node.js的模組載入流程

模組載入流程

檔案的快取區 有檔案模組快取區 和 原生模組快取區

  • require 方法接受一下幾種引數的傳遞: 1 http、fs、path等,原生模組 2 ./mod或../mod,相對路徑的檔案模組 3 /pathtomodule/mo,絕對路徑的檔案模組
  • mod,非原生模組的檔案模組

模組化程式碼案例

//main.js  主要呼叫模組的檔案
var Hello = require('./hello');

hello = new Hello();
hello.setName('Richard');
hello.sayHello();
//hello.js  模組檔案
function Hello(){
    var name ;
    this.setName = function(argName){
        name = argName
    }
    this.sayHello = function(){
        console.log('hellko' +  name);
    }
}

module.exports = Hello;
複製程式碼

函式

  • 在javascript 中,一個函式可以作為另一個函式的引數。
  • 我們可以先定義一個函式,然後傳遞,也可以在傳遞引數的地方直接定義函式。
  • Nodejs 中的函式使用與Javascript 類似

程式碼示例:

function say(word){
    console.log(word);
}
function execute(someFunction,value){
    someFunction(value);
}
execute(say,'hello')
複製程式碼

匿名函式

function execute(someFunction,value){
    someFunction(value)
}
execute(function(word){
    console.log(word)
},'hello');
複製程式碼

示例Ⅱ 同樣的功能,不同的實現方式

//匿名函式
var http = require('http');
http.createServer(function(request,response){
    response.writeHead(200,{"Content-Type":'text/plain'});
    response.write("Hello world");
    response.end();
}).listen(8000)


//先定義後傳遞

var http = require("http");
function onResquest(request,reponse){
    response.writeHead(200,{"Content-Type":'text/plain'});
    response.write("Hello World");
    response.end();
}
http.createServer(onResquest).listen(8888);
複製程式碼

路由

我們所需要的所有資料都會包含在request物件中,該物件作為onRequest()回撥函式的第一個引數傳遞。但是為了解析這些資料,我們需要額外的Node.JS模組,他們分別是urlquerystring模組

例如我們 訪問 http://localhost:8888/start?foo=bar&hello=world

                url.parse(string).query
                                    |
url.parse(string).pathname          |
                        |           |
                        |           |
                     ------ -------------------
http://localhost:8888/start?foo=bar&hello=world
                            ---       -----
                            |           |
                            |           |
querystring.parse(queryString)["foo"]   |
                                        |
                    querystring.parse(queryString)["hello"]
複製程式碼

//server.js
var http = require("http");
var url = require("url");
 
function start(route) {
  function onRequest(request, response) {
    var pathname = url.parse(request.url).pathname;
    //console.log("Request for " + pathname + " received.");
    route(pathname,response);
   
  }
 
  http.createServer(onRequest).listen(8888);
  console.log("Server has started.");
}
exports.start = start;

//router.js
function route(pathname,response) {
  if(pathname == '/'){
    response.writeHead(200, {"Content-Type": "text/plain"});
    response.write("Hello World");
    response.end();
  }else if(pathname == "/index/home"){
    response.end('index');
  }else{
    response.end('index');
  }
}
exports.route = route;

//app.js
var server = require("./server");
var router = require("./router");
 
server.start(router.route);
複製程式碼

獲取GET請求內容

var http = require('http');
var url = require('url');
var util = require('util');  //幫助類
 
http.createServer(function(req, res){
    res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});
    res.end(util.inspect(url.parse(req.url, true)));
}).listen(3000);
複製程式碼

獲取POST請求內容

var http = require('http');
var querystring = require('querystring');
var util = require('util');
 
http.createServer(function(req, res){
    // 定義了一個post變數,用於暫存請求體的資訊
    var post = '';     
 
    // 通過req的data事件監聽函式,每當接受到請求體的資料,就累加到post變數中
    req.on('data', function(chunk){    
        post += chunk;
    });
 
    // 在end事件觸發後,通過querystring.parse將post解析為真正的POST請求格式,然後向客戶端返回。
    req.on('end', function(){    
        post = querystring.parse(post);
        res.end(util.inspect(post));
    });
}).listen(3000);
複製程式碼

全域性物件與全域性變數

global 就是nodejs的全域性物件 類比javascript的window

  • __filename __filename 表示當前正在執行的指令碼的檔名。它將輸出檔案所在位置的絕對路徑,且和命令列引數所指定的檔名不一定相同。 如果在模組中,返回的值是模組檔案的路徑。

  • __dirname __dirname 表示當前執行指令碼所在的目錄。

  • setTimeout(cb, ms) setTimeout(cb, ms) 全域性函式在指定的毫秒(ms)數後執行指定函式(cb)。:setTimeout() 只執行一次指定函式。返回一個代表定時器的控制程式碼值。

  • clearTimeout(t) clearTimeout( t ) 全域性函式用於停止一個之前通過 setTimeout() 建立的定時器。 引數 t 是通過 setTimeout() 函式建立的定時器。

  • setInterval(cb, ms) setInterval(cb, ms) 全域性函式在指定的毫秒(ms)數後執行指定函式(cb)。返回一個代表定時器的控制程式碼值。可以使用 clearInterval(t) 函式來清除定時器。setInterval() 方法會不停地呼叫函式,直到 clearInterval() 被呼叫或視窗被關閉。

  • process process 是一個全域性變數,即 global 物件的屬性。它用於描述當前Node.js 程式狀態的物件,提供了一個與作業系統的簡單介面。通常在你寫本地命令列程式的時候,少不了要 和它打交道。下面將會介紹 process 物件的一些最常用的成員方法。

工具util

underscore.js

檔案系統

讀取檔案

var fs = require("fs");

// 非同步讀取
fs.readFile('input.txt', function (err, data) {
   if (err) {
       return console.error(err);
   }
   console.log("非同步讀取: " + data.toString());
});
// 同步讀取
var data = fs.readFileSync('input.txt');
console.log("同步讀取: " + data.toString());

console.log("程式執行完畢。");



複製程式碼

開啟檔案

fs.open(path, flags[, mode], callback) 引數說明:

  • path - 檔案的路徑。
  • flags - 檔案開啟的行為。
  • mode - 設定檔案模式(許可權),檔案建立預設許可權為 0666(可讀,可寫)。
  • callback - 回撥函式,帶有兩個引數如:callback(err, fd)。

獲取檔案資訊

fs.stat(path, callback) 引數說明

  • path - 檔案路徑。
  • callback - 回撥函式,帶有兩個引數如:(err, stats), stats 是 fs.Stats 物件。

寫入檔案

fs.writeFile(file, data[, options], callback)

  • file - 檔名或檔案描述符。
  • data - 要寫入檔案的資料,可以是 String(字串) 或 Buffer(緩衝) 物件。
  • options - 該引數是一個物件,包含 {encoding, mode, flag}。預設編碼為 utf8, 模式為 0666 , flag 為 'w'
  • callback - 回撥函式,回撥函式只包含錯誤資訊引數(err),在寫入失敗時返回。
var fs = require("fs");

console.log("準備寫入檔案");
fs.writeFile('input.txt', '我是通 過fs.writeFile 寫入檔案的內容',  function(err) {
   if (err) {
       return console.error(err);
   }
   console.log("資料寫入成功!");
   console.log("--------我是分割線-------------")
   console.log("讀取寫入的資料!");
   fs.readFile('input.txt', function (err, data) {
      if (err) {
         return console.error(err);
      }
      console.log("非同步讀取檔案資料: " + data.toString());
   });
});
複製程式碼

等等 方法 參考 菜鳥教程