最近學習的 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');