nodejs教程

一、概覽
1、html可以在瀏覽器直接打開運行,是因爲瀏覽器是html文件的解析器
而js文件不能在瀏覽器直接運行,是因爲瀏覽器不支持解析js文件,需要有一個解析器來解析js文件
可以下載安裝nodejs解析器,並且裏面自帶了npm,通過node.exe可以直接運行js文件,是通過命令行的形式運行的
要運行某個js文件,直接node + 要運行的js文件名稱或者直接是js代碼,按回車即可

js操作的是瀏覽器,node操作的是電腦系統、文件等等

2、編輯器也可以直接運行,推薦使用webstorm

3、在Ecmascript部分,node和js其實是一樣的,比如數據類型的定義、語法結構、內置對象
在js中的頂層對象:window
在node中的頂層對象:global,沒有window這個概念

二、模塊
es6通過import export來進行模塊化
nodejs通過require來進行模塊化
html通過script標籤來引入js文件
1、在nodeJs裏面,一個js文件就是一個模塊,每個模塊都有自己的作用域,
我們使用var聲明的變量,不是全局的,而是屬於當前模塊下的
比如:1.js
var a = 100;
console.log(a); //100
console.log(global.a); //undefined ,不是全局下面的變量
global.a = 200;
console.log(a); //100 仍然是開始定義的100
console.log(global.a); //這時候纔是200

2、filename:表示當前文件的絕對路徑
dirname:表示當前文件所在目錄的絕對路徑
它們並非全局的,而是模塊作用域下的
所以global.filename是訪問不到的,返回undefined
console.log(
filename); //E:\webstorm文件夾\index.js
console.log(__dirname); //E:\webstorm文件夾

3、模塊路徑
require(); //可以是絕對路徑、相對路徑
不能直接是require("1.js")這種不帶./的,這種加載方式,會加載node中的核心模塊,或者是node_modules裏面的慕課

4、查找文件:
首先按照加載的模塊的文件名進行查找;
如果沒有找到,則會在模塊文件名稱後面自動加上.js的後綴,然後進行查找;
如果還沒有找到,則會在模塊文件名稱後面自動加上.json的後綴,然後進行查找;
如果還沒有找到,則會在模塊文件名稱後面自動加上.node的後綴,然後進行查找;
如果還沒有找到,就會報錯。

5、
在一個模塊中,通過var定義的變量,其作用域範圍是當前模塊,外部不能夠直接訪問到;
如果我們想一個模塊能夠訪問另一個模塊中定義的變量,可以通過:

  • 把變量作爲global對象的一個屬性(不推薦)
    global.a = 100;
  • 使用模塊對象 module,這個對象不是全局的,而是每個模塊下的對象
    模塊對象 module用於:保存提供和當前模塊有關的一些信息,下面有很多屬性:
    nodejs教程
    exports:{}; //module的子對象,通過這個對象可以把一個模塊中的局部變量暴露出去,供外部訪問
    因爲exports也是一個對象,所以暴露變量出去之前,先聲明一個key值,value值就是這個局部變量
    var a = 100;
    module.exports.name = a;
    require();  //返回值就是module.exports對象

6、在模塊作用域下,還有一個內置的模塊對象,exports,它其實就是module.exports
所以:
module.exports.name = a; 可以寫成 exports.name = a;
【注意】:不要這樣操作
module.exports = [1,2,3]
也不要:exports = [1,2,3],只是追加屬性,不要修改

三、global對象 全局對象
局部:
filename
dirname
全局:
日期對象 var d = new Date()
數組 var arr = new Array(1,2,3)
定時器

三-1、process對象(進程對象)——全局對象
process === global.process //true
可以在任何地方都能訪問到,通過這個對象提供的屬性和方法,使我們可以對當前運行的程序的進程進行訪問和控制
1、process.argv
console.log(process.argv); // [ 'D:\Program Files\nodejs\node.exe', 'E:\webstorm文件夾\2.js' ]
第一個是解析器,第二個是js文件
如果帶上參數,那麼返回的數組裏面就會包含你運行時帶入的參數
舉例: node process.argv a=1 // [ 'D:\Program Files\nodejs\node.exe', 'E:\webstorm文件夾\2.js','a=1' ]
2、process.execPath
開啓當前進程的這個可執行文件的絕對路徑
3、env
返回用戶環境信息
4、version
返回node版本信息
5、versions
返回node以及node依賴包版本信息
6、pid
返回當前進程的pid 進程是node.exe
7、title
返回當前進程的顯示名稱(Getters/Setters)
8、arch
返回當前CPU處理器架構 arm/ia32/x64
9、platform
返回當前操作平臺
10、cwd()
返回當前進程的工作目錄
11、chdir(directory)
改變當前進程的工作目錄
12、memoryUsage()
返回node進程的內存使用情況,單位是byte
12、exit(code)
退出
13、kill(pid)
向進程發送信息
14、IO
a、stdin、stdout:標準輸入輸出流(IO)
標準輸入設備:向計算機輸入數據和信息的設備,是計算機與用戶或其他設備通信的橋樑。
例如:鼠標、鍵盤、攝像頭等等
標準輸出設備:是計算機硬件系統的終端設備,把計算機數據或信息以數字、字符、圖像、聲音等形式表現出來。例如:顯示器、打印等等
stdin、stdout提供了操作輸入數據和輸出數據的方法,我們也通常稱爲IO操作
stdin:標準輸入流
stdout:標準輸出流
console.log(...) === process.stdout.write(...);

b、默認情況下,輸入流是關閉的,要監聽處理輸入流數據,首先要開啓輸入流

//開啓
process.stdin.resume();
監聽用戶的輸入數據,輸入完成按下回車
process.stdin.on('data',function(chunk){
    console.log('用戶輸入了:'+chunk);
})

會一直監聽,用戶輸入完成按下回車顯示數據,再按下仍然會顯示第二次輸入的數據

四、Buffer類:類似數組
1、定義:一個用於更好的操作二進制數據的類
我們在操作文件或者網絡數據的時候,其實操作的就是二進制數據流;Node爲我們提供了一個更加方便的去操作這種數據流的類Buffer,他是一個全局的類,global.Buffer === buffer

JavaScript 語言自身只有字符串數據類型,沒有二進制數據類型。
但在處理像TCP流或文件流時,必須使用到二進制數據。因此在 Node.js中,定義了一個 Buffer 類,該類用來創建一個專門存放二進制數據的緩存區。
在 Node.js 中,Buffer 類是隨 Node 內核一起發佈的核心庫。Buffer 庫爲 Node.js 帶來了一種存儲原始數據的方法,可以讓 Node.js 處理二進制數據,每當需要在 Node.js 中處理I/O操作中移動的數據時,就有可能使用 Buffer 庫。原始數據存儲在 Buffer 類的實例中。一個 Buffer 類似於一個整數數組,但它對應於 V8 堆內存之外的一塊原始內存。

  • Buffer.alloc(size); 創建一個Buffer對象,並且爲這個對象分配一個空間大小,大小是size的8位字節;當我們爲一個buffer對象分配了一個空間大小以後,其長度是固定的,不能更改。也就是後續不能再增加內容了
    <Buffer 72 75 6e 6f 6f 62> //控制檯顯示的是16進制的
  • Buffer.from(array): 返回一個被 array 的值初始化的新的 Buffer 實例(傳入的 array 的元素只能是數字,不然就會自動被 0 覆蓋),聲明並賦值

  • Buffer.from(string[, encoding]): 返回一個被 string 的值初始化的新的 Buffer 實例,encoding默認是utf8

let bf2 = Buffer.from('miaov'); //bf2.length 5 返回的是字節數,不是字符串長度
let bf3 = Buffer.from('妙味'); //bf3.length 6 一個漢字佔據3個字節

2、Buffer類方法

  • bf.length; //buffer的字節長度
  • bf[ index ]; //獲取或者設置在index索引位置的8位字節內容
  • bf.write(string , [offset] , [length] , [encoding]); //根據參數offset偏移量和指定的encoding編碼方式,將參數string寫入數據寫入buffer
  • bf.toString( [encoding],[start],[end] ); //根據encoding返回一個解碼的string類型
  • bf.toJSON(); //返回一個JSON表示的Buffer實例,JSON.stringify將會默認調用來字符串序列化這個Buffer實例
  • bf.slice( [start],[end] ); //返回一個新的buffer,這個buffer將會和老的buffer引用相同的內存地址;
    注意:修改這個新的buffer實例slice切片,也會改變原來的buffer
  • bf.copy(targetBuffer[, targetStart[, sourceStart[, sourceEnd]]])
    let bf2 = Buffer.from('miaov');
    console.log(bf2);  //<Buffer 6d 69 61 6f 76>  //十六進制
    console.log(bf2.toString());  //'miaov'
    for (let i=0;i<bf2.length;i++){  //m的十六進制是6d;十進制是109;二進制是0110 1101
     console.log(bf2[i]);  //109 105 97 111 118  十進制
     console.log(String.fromCharCode(bf2[i]))  // m i a o v  圖形字符
    }
    let bf = Buffer.alloc(5);
    let str = 'miaov';
    //bf.write(str);
    //console.log(bf);  //<Buffer 6d 69 61 6f 76>
    // bf.write(str,1);
    // console.log(bf);  //從buffer第1位開始寫入,第0位用00補上,<Buffer 00 6d 69 61 6f>
    bf.write(str,1,3);
    console.log(bf);  //只寫入三位,其他位用00補上,<Buffer 00 6d 69 61 00>
    console.log(bf.toJSON());  //{ type: 'Buffer', data: [ 0, 109, 105, 97, 0 ] }

    3、Buffer中的靜態方法(又叫類方法,即不需要實例化即可使用的方法)

  • Buffer.isEncoding(encoding):如果給定的編碼encoding是有效的,返回true;否則返回false
  • Buffer.isBuffer(obj); 測試這個obj是否是一個Buffer
  • Buffer.byteLength(string,[encoding]):將會返回這個字符串的真實byte字節長度。encoding默認編碼是utf8
    let str1 = 'json';
    console.log(str1.length);  //4 字符長度
    console.log(Buffer.byteLength(str1));  //4 字節長度
  • Buffer.concat(list,[totalLength]):返回一個保存着將傳入Buffer數組中所有buffer對象拼接在一起的buffer對象
    list是buffer對象,返回值是多個buffer對象拼接成的一個buffer對象
    totalLength是拼接後的字節長度,不傳是計算後的所有的字節長度,(建議預先設置,節省計算時間)

五、文件系統模塊 File System
1、該模塊是核心模塊,需要使用require導入後使用:let fs = require('fs');
2、該模塊提供了操作文件的一些API

  • 異步的打開一個文件:
    fs.open(path,flags,[mode],callback)
    path:要打開文件的路徑;
    flags:打開文件的方式:讀/寫
    mode:設置文件的模式:讀/寫/執行
    callback:回調函數,接受2個參數:err、fd
    err:文件打開失敗的錯誤保存在err裏面,如果成功err爲null
    fd:被打開文件的標識,和定時器類似,用於後續要操作文件的標識,即後續如果要操作某個打開的文件,把這個文件標識傳到後續操作的某些方法裏面去,即可知道操作的是當前文件

  • fs.open()的同步版:
    fs.openSync(path,flags,[mode])

  • 從指定的文檔標識符fd讀取文件數據
    fs.read(fd,buffer,offset,length,position)
    fd:通過open方法成功打開一個文件返回的編號
    buffer:buffer對象,用於存儲打開文件內部的信息
    offset:偏移量,數據從buffer對象裏面的第幾位開始存儲,起始是0
    length: 讀取的內容長度
    position:從文件的第幾位開始讀取,默認是0,即從頭開始
    callback:接受三個參數,err錯誤信息、length返回的新的buffer對象的長度;newBf:返回的新的buffer對象

  • fs.read的同步版本,返回bytesRead的個數
    fs.readSync(fd,buffer,offset,length,position,callback)

*通過文件標識fd,向指定的文件中寫入buffer
fs.write(fd,buffer,offset,length,[position],callback)
同步版本:fs.writeSync(fd,buffer,offset,length,[position])
fd:通過open方法成功打開一個文件返回的編號
buffer:要寫入到文件的數據
offset:從buffer對象中第幾位開始寫入數據,默認是0
length: 要寫入的buffer數據的長度
position:向指定的文件的第幾位開始寫入buffer數據,默認是0,即從頭開始寫入數據,如果開頭已經有數據,那麼新的數據會覆蓋原始數據
callback:接受三個參數,err錯誤信息、length寫入數據的buffer對象的長度;newBf:寫入數據的buffer對象

*通過文件標識fd,把data寫入到文檔中,如果data不是buffer對象的實例,則會把值強制轉換成爲一個字符串
fs.write(fd,data,[position],[encoding],callback)
同步版本:fs.writeSync(fd,data,[position],[encoding])
data:直接是一個字符串,此時不再從第幾位寫入了,而是全部寫入到文件裏,所以沒有offset參數

  • 關閉一個打開的文件
    fs.close(fd,callback)
    同步版本:fs.closeSync(fd)

六、更好用的文件系統方法
1、fs.writeFile(filename,data,[options],callback)
異步的將數據寫入一個文件,如果文件不存在就新建,如果文件原先存在,則會被替換;data可以是一個string,也可以是一個原生buffer
同步版本:fs.writeFileSync(filename,data,[options])

2、fs.appendFile(filename,data,[options],callback)
異步的將數據添加到一個文件的尾部,如果文件不存在就新建,如果文件原先存在,則會將數據追加到文件的尾部;data可以是一個string,也可以是一個原生buffer
同步版本:fs.appendFileSync(filename,data,[options])

3、fs.readFile(filename,[options],callabck)
異步讀取一個文件的全部內容
同步版本:fs.readFileSync(filename,[options])

4、fs.exists(path,callback)
檢查指定路徑的文件或者目錄是否存在
同步版本:fs.existsSync(path)

5、fs.unlink(path,callback)
刪除一個文件
同步版本:fs.unlink(path)

let fs = require('fs');
let filename = '2.txt';
//異步
if(fs.exists(filename,(err)=>{
    if(!err){
        fs.writeFile(filename,'hello',(err)=>{
            if(err){
                console.log("文件創建失敗")
            }else{
                console.log("文件創建成功")
            }
        })
    }else{
        fs.appendFile(filename,'-world',(err)=>{
            if(err){
                console.log('文件追加失敗')
            }else{
                console.log('文件追加成功')
            }
        })
    }
}));
//同步
if(!fs.existsSync(filename)){
    console.log('文件創建成功');
    fs.writeFileSync(filename,'hello')
}else{
    console.log('文件追加成功');
    fs.appendFileSync(filename,'-world')
}

6、fs.rename(oldPath,newPath,callback)
重命名
同步版本:fs.renameSync(oldPath,newPath)

7、fs.stat(path,callback)
讀取文件信息的狀態,不是文件內部的內容,返回值是一個json,包括文件類型、文件日期、文件大小等等
mode=33206表示該文件是文件類型,mode=16822表示該文件是文件夾
同步版本:fs.statSync(path)

8、fs.watch(filename,[options],[listener])
觀察指定路徑的改變,filename可以是文件或者目錄
//listener是一個監聽器,回調函數,有2個參數:事件event和被監聽文件的名稱filename

9、fs.mkdir(path,[mode],callback) //mode模式,是隻讀還是讀寫模式
創建文件夾
同步版本:fs.mkdirSync(path,[mode])

10、fs.readdir(path,callback)
讀取文件夾
同步版本:fs.readdirSync(path)
回調函數包括2個參數,err錯誤信息和當前文件夾下面所有的文件和文件夾信息fileList

11、fs.rmdir(path,callback)
刪除文件夾
同步版本:fs.rmdirSync(path)

七、使用node進行web開發
1、用戶上網流程
用戶輸入https://www.baidu.com/
通過瀏覽器發送https請求(類似於打電話撥號),請求baidu.com,這個域名可以轉換爲ip地址
通過ip定位,到網絡中指定的一臺機器上,然後該機器會接收到該用戶發送過來的請求,然後對該請求進行處理,返回對應的內容

簡言之:
用戶通過瀏覽器發送一個http請求到指定的服務器
服務器接收到該請求,對該請求進行分析和處理
服務器處理完成之後,返回對應的數據到用戶機器
瀏覽器接受到服務器返回的數據,並根據接收到的數據進行分析和處理

web開發:就是兩臺機器之間的數據交互,客戶端與服務端的交互
由客戶端發送一個http請求到指定的服務端 ——> 服務端接收並處理請求 ——> 返回數據到客戶端,類比迅雷下載
http協議:

要進行web開發,首先就必須處理關於服務端接收請求的這一過程,所以要搭建服務器,該服務器可以接收來自任何客戶端的鏈接和請求,然後進行對應處理

2、http模塊
let http = require('http');
使用該模塊可以進行服務器的搭建
nodejs教程
nodejs教程

nodejs教程

server.listen(); //如果不傳參數,默認系統會自動分配端口號,但是不建議,要主動設置端口號及主機名

res.writeHead( 200,'',{ //200,默認返回ok
content-type : 'text/html;charset=utf-8' //會將返回信息當成html輸出到頁面,html標籤起作用
content-type : 'text/plain' //會將返回信息當成文本文件輸出到頁面,html標籤不起作用
} )

/*
* 搭建一個http的服務器,用於處理用戶發送的http請求
* 需要使用node提供一個模塊  http
* */
//加載一個http模塊
let http = require('http');
//通過http模塊下的createServer創建並返回一個web服務器對象
let server = http.createServer();
server.on('error',(err)=>{
    console.log(err)
})
server.on('listening',()=>{
    console.log('linstening...')
})
server.on('request',(req,res)=>{  //req是客戶端發送的數據,res是服務端返回的數據
    console.log('有客戶端請求了')
    //console.log(req);  //req裏面有請求頭、域名後面附帶的路徑信息/a/index.html、method方式
    //console.log(res);  //res裏面包括response正文信息(即網頁上顯示的內容)以及正文之外的一些信息,比如返回頭信息(網頁上不可見)
    res.writeHead('200','',{
        'content-type':'text/html;charset=utf-8'
    })
    // res.write('<h1>hello</h1>');
    // res.end();
    //可以合併爲一步
    res.end('<h1>hello</h1>');
})
server.listen(8080,'localhost');

3、url模塊
nodejs教程

let url = require('url');
url.parse(); //專門用於解析url路徑,返回json格式數據

4、使用querystring模塊方法對get和post提交的數據進行處理
nodejs教程

let qs = require('querystring');
get方式發送數據
qs.parse('foo=bar&abc=xyz&abc=123'); //{foo: 'bar',abc: ['xyz', '123']}

post方式發送數據

let http = require('http');
let url = require('url');
let fs = require('fs');
let qs = require('querystring');
let server = http.createServer();
let filename = __dirname + '/html/';
server.on('error',(err)=>{
    console.log(err)
})
server.on('listening',()=>{
    console.log('listening')
})
server.on('request',(req,res)=>{
    var urlStr = url.parse( req.url );  //返回一個對象,裏面的pathname屬性和req.url一樣
    switch (urlStr.pathname) {
        case '/':
            getData(filename+'index.html',req,res);
            break;
        case '/user':
            getData(filename+'user.html',req,res);
            break;
        case '/login':
            getData(filename+'login.html',req,res);
            break;
        case '/login/check':
            /*console.log(req.method);  //get
            console.log(urlStr.query);  //username=xiaoxiao&password=1
            console.log(qs.parse(urlStr.query));  //[Object: null prototype] { username: 'xiaoxiao', password: '1' }*/
            if(req.method.toUpperCase() === 'POST'){
                let str = '';
                req.on('data',(chunk)=>{
                    str += chunk;
                })
                req.on('end',()=>{
                    console.log(str);  //username=13795232495&password=111
                    console.log(qs.parse(str));  //[Object: null prototype] { username: '13795232495', password: '111' }
                })
            }
            break;
        default:
            break;
    }
})
function getData(filename,req,res) {
    fs.readFile(filename,(err,data)=>{
        //console.log(data.toString());  //輸出頁面內的全部標籤內容
        if(err){
            res.writeHead(404,'',{
                'content-type':'text/html;charset=utf8'
            })
            res.end('<h1>404</h1>')
        }else{
            res.writeHead(200,'',{
                'content-type':'text/html;charset=utf8'
            })
            res.end(data)
        }
    })
}
server.listen(8082,'localhost');
/*
* 搭建一個http的服務器,用於處理用戶發送的http請求
* 需要使用node提供一個模塊  http
* */
//加載一個http模塊
let http = require('http');
let url = require('url');
//通過http模塊下的createServer創建並返回一個web服務器對象
let server = http.createServer();
server.on('error',(err)=>{
    console.log(err)
})
server.on('listening',()=>{
    console.log('linstening...')
})
server.on('request',(req,res)=>{  //req是客戶端發送的數據,res是服務端返回的數據
    console.log('有客戶端請求了')
    console.log(req.url);  //req裏面有請求頭、域名後面附帶的路徑信息/a/index.html、method方式
    //console.log(res);  //res裏面包括response正文信息(即網頁上顯示的內容)以及正文之外的一些信息,比如返回頭信息(網頁上不可見)
    switch (req.url) {
        case '/':
            res.writeHead(200,'',{
                'content-type':'text/html;charset=utf-8'
            })
            res.end('<h1>這是首頁</h1>');
            break;
        case '/user':
            res.writeHead(200,'',{
                'content-type':'text/html;charset=utf-8'
            })
            res.end('<h1>這是用戶頁</h1>');
            break;
        default:
            res.writeHead(404,'',{
                'content-type':'text/html;charset=utf-8'
            })
            res.end('<h1>404</h1>');
            break;
    }

    // res.write('<h1>hello</h1>');
    // res.end();
    //可以合併爲一步
    //res.end('<h1>hello</h1>')

})
server.listen(8080,'localhost');

【注意】
1、所謂異步,就是執行成功了之後會執行一個回調函數,下面的代碼會繼續執行,即使報錯了也不妨礙下面代碼的執行;同步,就是成功了就繼續執行下面的代碼,報錯了就卡在這兒了,下面的代碼也就執行不了了。
2、所謂的參數filename,包括文件的名稱和路徑(如果有路徑的話),比如在task文件夾下創建index.html
那麼filename='task/index.html'
要包括文件的名稱,不能僅僅是一個空路徑,'task/'

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章