1. 程式人生 > >最近學習的 Node.js 基礎:安裝、環境配置、forever

最近學習的 Node.js 基礎:安裝、環境配置、forever

最近工作中,因為某某某某原因,需要用到Node.js  。 

發現在很多方面和python很像,比如generator / yield ,比如模組的使用方式,比如http模組。

 

先安裝個環境,windows沒什麼難度,下載個安裝包裝一下就行,主要看一下centos的

並且修改了npm源為淘寶源,主要是下載速度快。並且安裝了forever元件,作為伺服器的 node 伺服器守護程式。

複製程式碼
// centos6.5下安裝

// 官網下載: https://nodejs.org/en/download/
// 或者淘寶映象下載 https://npm.taobao.org/mirrors/node/v8.11.4/

// node-v8.11.4-linux-x64.tar.gz
// 不建議原始碼編譯, 速度太慢.

tar zxvf node-v8.11.4-linux-x64.tar.gz 
mv node-v8.11.4-linux-x64 node-v8.11.4

vim /etc/profile 
// 增加下面2行
export NODE_HOME=/opt/node-v8.11.4
export PATH=$NODE_HOME/bin:$PATH

// 最後執行 node -v 
// npm -v 
// 如果這2個命令能正確執行,即安裝成功. 

// 改成淘寶映象 後續就可以使用cnpm 命令了.
npm install -g cnpm --registry=https://registry.npm.taobao.org

// 裝個forever 試試 這個一般用於生產環境作為node伺服器
cnpm install forever -g
複製程式碼

 

npm install 可以簡寫為 npm i 

npm 的命令很簡單易理解。 直接命令 npm 回車,會給出幫助, npm -l 會給出更詳細的幫助。 npm <cmd> -h  會給出針對 cmd命令的幫助

 

nrm 是一個管理 npm 源的工具。用來切換官方 npm 源和國內的 npm 源(如: cnpm),當然也可以用來切換官方 npm 源和公司私有 npm 源。

全域性安裝 nrm:

npm i nrm -g
nrm ls   # 檢視源列表,有 * 的為當前使用的源

nrm use taobao  # 切換為 taobao 源

 

forever的元件簡單易用,並且較為穩定。forever可以看做是一個nodejs的守護程序,能夠啟動,停止,重啟我們的app應用。

 Github地址:https://github.com/nodejitsu/forever  不過,看起來,最後的更新都停在2年前了。

另外一個nodejs守護程序 pm2 一直有更新,可參考此文安裝配置使用:https://blog.csdn.net/maquealone/article/details/79550120

複製程式碼
forever    # 顯示幫助

forever start app.js   # 簡單啟動app

# 追加至日誌,forever預設是不能覆蓋上次的啟動日誌, // 所以如果第二次啟動不加-a,則會不讓執行 
forever start -l forever.log -a app.js   

forever list    # 檢視到當前執行的所有服務

forever stopall   # 停止所有執行服務

forever stop app.js    # 停止指定檔案服務

forever restart app.js     # 和停止服務方式一樣
forever restartall    # 重啟全部
複製程式碼

 

 

開始:第一個js

複製程式碼
let time=0;  // 初始化時間為0

// 設定一個定時器, 每隔半秒輸出一個內容.
let tmr = setInterval(function () {
    console.log('aaaaaaaaaaaaaaa ' + time);
    time ++;
    if(time>=5){
        clearInterval(tmr);
    }
},500);


console.log(__dirname); //所在路徑
console.log(__filename);  //完整路徑及檔名
複製程式碼

 

簡單的函式示例:

複製程式碼
// // 兩種函式的寫法
// function sayHi() {
//     console.log('hi');
// }
//
// sayHi();
//
// let sayBye=function () {
//     console.log("bye,");
// }
//
// sayBye();



/* 回撥函式 */
// function callFunc(fun) {
//     fun();
// }
//
// let sayHello = function(){
//     console.log("Hello.");
// }
//
// callFunc(sayHello); // 輸出Hello.


// 帶有引數的回撥函式
function callFunc(func,name) {
    func(name);
}

let sayHello = function (name) {
    console.log('Hello, '+name);
};

callFunc(sayHello,'Jerry');


// 或者這樣寫
function foo(fun,name) {
    fun(name);
}

foo(function (name) {
    console.log(name + ' world.')
},'Hello');
複製程式碼

 

自定義簡單模組:b03_model_count.js

複製程式碼
let counter = function (arr) {
    return "There are " + arr.length + " elements in array.";
};

let addr = function (a, b) {
    return a + b;
};

let pi = 3.14;

// module.exports.cnt = counter;
// module.exports.add = addr;
// module.exports.pi = pi;

// 或者寫成鍵值對
module.exports = {
    cnt:counter,
    add:addr,
    pi:pi
};
複製程式碼

b03_model_count2.js

複製程式碼
let addr = function (a, b) {
    return a + b;
};

let pi = 3.1415926;


// 或者寫成鍵值對, 但是這樣不易閱讀
module.exports = {
    cnt:function (arr) {
        return "There are " + arr.length + " elements in array.";
    },
    add:addr,
    pi:pi,
};
複製程式碼

b03_model_app.js  這個檔案中使用了上面兩個自定義的模組。

複製程式碼
let ss = require('./b03_model_count');

let pi = require('./b03_model_count2').pi;

console.log(ss.cnt([1,3,4,5]));
console.log(ss.add(3,9));
console.log(ss.pi);
console.log(pi);
複製程式碼

 

事件 events

複製程式碼
let events = require('events');

// 建立 eventEmitter 物件
let testEmiter = new events.EventEmitter();

// 註冊事件監聽器  事件名是一個字串,通常表達一定的語義 some_events
testEmiter.on('some_events',function (msg) {
    console.log(msg,' 執行事件繫結的匿名函式 ');
});

// on 函式用於繫結事件函式,emit 屬性用於觸發一個事件。
testEmiter.emit('some_events',"what the fuck ?");


// 參考 http://www.runoob.com/nodejs/nodejs-event.html
複製程式碼

events 例一

複製程式碼
const events = require('events');
const util = require('util');

let Person = function (name) {
    this.name = name;
};

// 使用繼承工具,讓 Person類去繼承 events.EventEmitter
util.inherits(Person, events.EventEmitter);

let alex = new Person('alex');
let jerry = new Person('jerry');
let tom = new Person('tom');

// 將三個物件賦給陣列
let ps = [alex, jerry, tom];

// 列表物件的遍歷方法
ps.forEach(function (person) {
    person.on('speak', function (msg) {
        console.log(person.name + " said: " + msg)
    });

    person.on('run', function (res) {
        console.log(person.name + ' run ' + res);
    });
});

// 觸發事件
alex.emit('speak', '第二個引數 msg ');
jerry.emit('speak', '說什麼呢?');
tom.emit('run', '500m');
複製程式碼

events 例二 

複製程式碼
const events=require('events');
const util = require('util');

let Person=function(name){
    this.name=name;
};

util.inherits(Person,events.EventEmitter);

let lucy=new Person("Lucy");
let jim=new Person("Jim");

let ps=[lucy,jim];

ps.forEach(function (psn) {
    psn.on('say',function (msg) {
        console.log(psn.name + " say: " + msg);
    });
});

lucy.emit('say',"你制杖嗎?");
jim.emit('say',"不,我販劍.");
複製程式碼

 

檔案的非同步方式與同步方式 讀寫

複製程式碼
let fs = require('fs');

// 讀檔案 同步的方法
// let rs = fs.readFileSync("a.txt",'utf8');
// console.log(rs);

// 非同步讀檔案
// let rs = fs.readFile("a.txt","utf8",function (err,data) {
//     console.log(data);
// });

// 非同步方法
fs.readFile('a.txt','utf8',function (err,data) {
    // 非同步寫
    fs.writeFile('d.txt', data, function () {
        console.log('複製成功');
    })
});
console.log("finished");
複製程式碼

目錄與檔案的建立與刪除

複製程式碼
let fs = require('fs');

// 建立目錄 同步
// fs.mkdirSync('aaa');
// 刪除目錄 同步
// fs.rmdirSync('aaa');

// 非同步方式 建立目錄 讀檔案 寫檔案
fs.mkdir('./newdir',function () {
    fs.readFile('a.txt','utf8',function (err,data) {
        fs.writeFile('./newdir/c.txt',data,function () {
            console.log('copy success.');
        });
    });
});
// 即使目錄存在, 多次執行也不會出錯.
// 巢狀寫法難以理解. 會有更好的寫法來解決.


// 非同步刪除  先刪除檔案, 再刪除目錄. 非空目錄則刪除不成功.
fs.unlink('./newdir/c.txt', function () {
    fs.rmdir('./newdir',function () {
        console.log('delete success.')
    });
});
複製程式碼

 

資料流 stream  優點是簡單方便

複製程式碼
const fs = require('fs');

let myReadStream = fs.createReadStream(__dirname + '/a.txt');
let myWriteStream = fs.createWriteStream(__dirname + '/c.txt');


// myReadStream.setEncoding('utf8');
//
// // 讀取後直接寫入
// myReadStream.on('data',function (chunk) {
//     myWriteStream.write(chunk);
// });
//
// myReadStream.on('end',function () {
//     console.log('copy success.');
// });


// let wd = '你好,這是一個測試.';
//
// myWriteStream.write(wd);
// myWriteStream.end();
// myWriteStream.on('finish',function () {
//     console.log('finished.');
// });


// 使用管道一行就搞定
myReadStream.pipe(myWriteStream);
複製程式碼 複製程式碼
const fs = require('fs');

// let myReadStream = fs.createReadStream(__dirname + "/a.txt",'utf8'); // 讀取時加上編碼
let myReadStream = fs.createReadStream("./a.txt",'utf8');
/*
// myReadStream.setEncoding('utf-8'); // 另外設定編碼

myReadStream.on('data', function (chunk) {
    console.log('new chunk received');
    console.log(chunk); // 得到Buffer Buffer滿後,會自動建立另一個Buffer, 如果內容過大,會出現多個Buffer
    // console.log(chunk.toString()); // 如果讀取時設定了編碼,則不必toString()
});
*/


// 如下方法,得到拼接後完整的檔案
let data = "";

myReadStream.on('data', function (chunk) {
    data += chunk;
});

myReadStream.on('end',function () {
    console.log(data);
});
複製程式碼

stream例子:

複製程式碼
/**
 * 加密並壓縮文件:
 * 但是: 加密之後,壓縮率為0
 * 若不加密,壓縮率較高
 */

const crypto = require('crypto');
const fs = require('fs');
const zlib = require('zlib');

let pwd = new Buffer(process.env.PASS || '123456');
let encryptStream = crypto.createCipher('aes-256-cbc', pwd); // 加密函式

let gzip = zlib.createGzip(); // 壓縮
let readStream = fs.createReadStream(__dirname + '/a.txt');
let writeStream = fs.createWriteStream(__dirname + '/out.gz');

// 使用多個管道
readStream
    .pipe(encryptStream)  // 加密
    .pipe(gzip)           // 壓縮 加密之後,壓縮率為0
    .pipe(writeStream)    // 寫入檔案
    .on('finish', function () {
        console.log('done.');
    });
複製程式碼

 

資料型別

複製程式碼
function show(x) {

    console.log(typeof x);    // undefined
    console.log(typeof 10);   // number
    console.log(typeof 'abc'); // string
    console.log(typeof true);  // boolean

    console.log(typeof function () {});  //function

    console.log(typeof [1, 'a', true]);    //object
    console.log(typeof { a: 10, b: 20 });  //object
    console.log(typeof null);              //object
    console.log(typeof new Number(10));    //object
}
show();


let fn = function () { };
// 判斷型別
console.log(fn instanceof Object);  // true


// 定義一個函式
let fnc = function () {
    console.log(100);
};

// 將若干物件賦給函式的屬性
fnc.a = 10;
fnc.b = function () {
    alert(123);
};
fnc.c = {
    name: "Harry potter",
    year: 2000
};

fnc();
console.log(fnc.c);
複製程式碼

 

複製程式碼
function Fn() {
    this.name = 'Harry potter';
    this.year = 2000;
}
let fn1 = new Fn();
console.log(typeof(fn1));               // object
console.log(fn1 instanceof Object);     // true
console.log(fn1 instanceof Function);   // false

console.log('-----------------------');
// var obj = new Object();
// obj.a = 10;
// obj.b = 20;
//
// var arr = new Array();
// arr[0] = 5;
// arr[1] = 'x';
// arr[2] = true;


// 語法糖 比上面寫法更簡便
let obj = { a: 10, b: 20 };
let arr = [5, 'x', true];

console.log(obj instanceof Object);  //true
console.log(arr instanceof Object);  //true

console.log(typeof(Object)); // function
console.log(typeof(Array));  // function
console.log(typeof(obj));  // object
console.log(typeof(arr));  // object
複製程式碼

 

字串轉時間:

var cur_time = '20181112155323';
var pattern = /(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/;
var dd = cur_time.replace(pattern, '$1-$2-$3 $4:$5:$6');
console.log(dd);

 

 

下面是段亂入的 http server 程式碼,先不要管它。實現對一個http請求的簡單響應。用到3個模組:http, fs 檔案,path 路徑

複製程式碼
const http = require('http');
const fs = require('fs');
const path = require('path');
//核心模組總是被優先載入,如果它們被require()呼叫。require('http')將總是返回內建的HTTP模組,即便有一個同名檔案存在。

let onReq = function (req, res) {
    console.log('recv a req:');
    res.writeHead(200, {'Content-Type': 'text/html;charset=utf-8'});

    let wwwdir = path.resolve(__dirname, '../www');

    let readStream = fs.createReadStream(wwwdir + '/bbb.html');
    readStream.pipe(res);

};

let server = http.createServer(onReq);
server.listen(80, '0.0.0.0');
複製程式碼