JS筆記(21): NODE

1、關於node

1) NODE概念

基於V8引擎(谷歌瀏覽器的引擎)渲染JS的工具或者環境javascript

  • 安裝node(到node官網http://nodejs.cn/下載便可)
  • 把js代碼放到node環境中執行

2) NODE安裝完以後

  • 當前電腦後自動安裝了npm(node Package Managernode模塊管理器):一個js模塊(全部封裝好可供其餘人調取使用的稱之爲模塊或者包)管理的工具,基於npm能夠安裝下載js模塊
  • 他會生成node執行的命令(能夠在DOS窗口或者終端命令中執行):node xxx.js

3) 如何在NODE中渲染和解析JS

  • REPL模式:Read-Evaluate-Print-Loop 輸入-求值-輸出-循環
  • 直接基於node來執行JS文件
    • 在命令窗口中執行(DOS窗口 & 終端窗口)

多數人把node稱之爲後臺編程語言,是由於:css

  • 1)咱們能夠把node安裝在服務器上
  • 2)咱們能夠把編寫的js代碼放到服務器上,經過node執行(咱們可使用js來操做服務器,換句話說,使用js來實現服務器端的一些功能操做)

4) NODE的優點和特色:

傳統後臺語言:JAVA/Python/PHP/C#html

  • 單線程
  • 基於V8引擎渲染:快
  • 異步無阻塞的I/O操做:I=>input O=>ouput 對文件的讀寫
  • Event-driven事件驅動:相似於發佈訂閱或者回調函數
  • JS運行在客戶端瀏覽器中=>前端
    • 瀏覽器給js提供不少全局的屬性和方法 window.setTimeout...
  • JS運行在服務器端的node中=>後臺
    • NODE也給js提供不少內置的屬性和方法:http/fs/url/path...等對象中都提供不少API供js操做
  • 前端(瀏覽器運行js)是限制I/O操做的
    • input type='file' 這種算是I/O操做,可是須要用戶手動選擇(並且僅僅是讀取不是寫入)
  • 後端(node中運行js) 不限制I/O操做

5) node中的模塊

node自己是基於commonJS模塊規範設計的,因此模塊式node的組成前端

  • 內置模塊:node天生提供的js調取使用的
  • 第三方模塊:別人寫好的,咱們能夠基於npm安裝使用
  • 自定義模塊:本身建立的一些模塊

2、CommonJS規範

參考: CommonJS:模塊設計思想(AMD/CMD/ES6 MOUDLE 都是模塊化設計思想)java

  • CommonJS規定,每個js都是一個單獨的模塊(模塊是私有的:裏面涉及的值和變量以及函數都是私有的,和其餘js文件中的內容是不衝突的)
  • CommonJS中能夠容許模塊中的方法互相的調用
    • B模塊中想要調取A模塊中的方法
    • => A導出
    • => B導入

1) 導出

CommonJS給每個模塊(每個js)中都設置了內置的變量/屬性/方法node

  • module: 表明當前這個模塊對象[object]
  • module.exports: 模塊的這個屬性是用來導出屬性方法的[object]
  • exports: 是內置的一個變量,也是用來導出當前模塊屬性方法的,雖然和module.exports不是一個東西,可是對應的值是一個(module.exports=exports 值都是對象)

2) 導入

  • require: CommonJS提供的內置變量,用來導入模塊的(其實導入的是moudle.exports暴露出來的東西)
    • 導入的值是對象[object]

3) require導入的時候:

  • 首先把about_node.js模塊中的代碼自上而下執行,把exports對應對內存導入進來,因此接受的結果是一個對象
  • require是一個同步操做:只有把導入的模塊代碼執行完成,才能夠獲取值,而後繼續執行本模塊下面的代碼
  • let temp1 = require('./about_node'); //=> ./ 是特地指定當前目錄中的某個模塊(.js能夠省略)

4) require導入規則:

  • require('./xxx') 或者../xxx 或者 /xxx

這種本身制定的路徑的模式,都是爲了導入自定義的模塊,換句話說,想要導入自定義的模塊,必須加路徑jquery

  • require('./xxx')

首先到當前項目中的node_modules中查找是否存在這個模塊,不存在找node提供的內置模塊(導入第三方或者內置的)web

5) CommonJS的特色:

  • 全部代碼都運行在模塊做用域,不會污染全局做用域(每個模塊都是私有的,包括裏面全部的東西也都是私有的,不會和其餘模塊產生干擾)
  • 模塊能夠屢次加載,可是隻會在第一次加載時運行一次,而後運行結果就被緩存了,之後再加載,就直接讀取緩存結果,要想讓模塊再次運行,必須清除緩存(爲了保證性能,減小模塊代碼重複執行的次數)
  • 模塊加載的順序,按照其在代碼中出現的順序,CommonJS規範加載模塊是同步的,只有加載完成,才能執行後面的操做

3、內置變量__dirname & __filename

  • __dirname: 模塊中這個內置變量是當前模塊所在的絕對路徑(具體到盤符:物理路徑)
    • console.log(__dirname)
    • C:\Users\lenovo\Desktop\notes\NODE
  • __filename: 相對於_dirname來說,多了模塊名稱 (即對了文件名稱)
    • C:\Users\lenovo\Desktop\notes\NODE\about_node.js

示例

// about_node.js
let a = 12;
let fn = b => {
    return a * b
}
// console.log(1)
// setTimeout(()=>{
// console.log(1.5)
// },1000)
exports.fn = fn; // 把當前模塊私有的函數放到exports導出對象中(賦值給他的某一個屬性),這樣在其餘模塊中,能夠基於require導入進來使用 <=> moudle.exports.fn = fn
// console.log(2)

console.log(__dirname); //C:\Users\lenovo\Desktop\notes\NODE
console.log(__filename) //C:\Users\lenovo\Desktop\notes\NODE\about_node.js
複製代碼
// about_node2.js
let a = 2;
let fn = b => {
    return a / b
}
let temp1 = require('./about_node'); // ./ 是特地指定當前目錄中的某個模塊(.js能夠省略)
// console.log(3); // 1 2 3 先把about_node.js中的代碼所有執行完,再執行about_node2.js中的代碼
// // 若是加定時器 1 2 3 1.5
// console.log(temp1); //此時temp1是個對象 {fn:...}
console.log(temp1.fn(10)); //120 用的是about_node.js中的變量a和fn

// // 第二次並無把about_node.js執行,由於第一次執行把導出的結果緩存了 但不多寫兩次
// temp1 = require('./about_node');
// console.log(temp1.fn(10)); //120
複製代碼

4、fs內置模塊

【內置模塊fs:實現I/O操做】ajax

經常使用方法:sql

  • fs.mkdir / fs.mkdirSync:建立文件夾 有Sync的是同步建立,反之是異步,想要實現無阻塞I/O操做,咱們通常用異步完成 fs.mkdir(path,callback) fs.mkdirSync(path)`
  • fs.readsir / fs.readdirSync:讀取文件目錄中的內容
  • fs.rmdir / fs.rmdirSync:刪除文件夾(若是文件夾中有內容不能刪除)
  • fs.readFile:讀取文件中內容
  • fs.writeFile:向文件中寫入內容(覆蓋寫入:寫入的新內容會替換原有內容)
  • fs.appendFile:追加寫入新內容,原有內容還在
  • fs.copyFile:拷貝文件到新的位置
  • fs.unlink:刪除文件
let fs = require('fs');

//建立文件夾 同步會形成阻塞,通常用異步
fs.mkdir('./less',(err)=>{
    if(err){
        console.log(err);
        return;
    }
    console.log('ok');
});
console.log(1);

//讀取文件目錄 異步
fs.readdir('./',(err,result)=>{
    if(err){、
        // console.log(err);
        return;
    };
    console.log(result); // 當前文件目錄 ['less', 'module_fs.js'] 返回結果是一個數組
});

//刪除文件夾 (必須保證文件夾是空的)
fs.rmdir('./less',err=>{
    if(err){
        console.log(err);
        return;
    }
    console.log('ok');
})
/* 若是文件夾中有內容 則會報錯{ [Error: ENOTEMPTY: directory not empty, rmdir 'C:\Users\lenovo\Desktop\notes\NODE\module_fs\less'] */

// 讀取文件內容
fs.readFile('./less/less.js','utf-8',(err,result)=>{
    if(err){
        // console.log(err);
        return;
    }
    console.log(result);//文件內容(字符串格式) setTimeout(()=>{console.log(123) },1000)
    // 不設置utf-8編碼格式,讀取出來的是buffer格式的數據,設置事後是字符串格式數據
})

// 向文件中寫入內容(覆蓋寫入)
fs.writeFile('./less/less.js','哈哈','utf-8',(err)=>{
    //第二個參數是文件寫入的內容 會覆蓋原內容
})

// 向文件中寫入內容(追加寫入)
fs.appendFile('./less/less.js','嘿嘿','utf-8',(err)=>{
    //第二個參數是文件寫入的內容 追加在原內容後
})

// 刪除文件
fs.unlink('./less/less.js',(err)=>{
    if(err){
        return;
    }
    console.log('ok')
})
複製代碼

5、url內置模塊

【url內置模塊】

url.parse(url[,flag]):

  • 把一個url地址進行解析,把地址中的每一部分按照對象鍵值對的方式存儲起來
  • 第二個參數默認爲false,設置爲true能夠把問號傳參的部分也解析爲對象鍵值對的方式
    • 第二個參數false/true區別: query: [Object: null prototype] { from: 'qq', lx: 'stu' },

Url {

  • protocol: 'http:', //=>協議
  • slashes: true, //=>是否有雙斜線
  • auth: null, //=>
  • host: 'baidu.com', //=>域名+端口
  • port: null, //=>端口
  • hostname: 'baidu.com', //=>域名
  • hash: '#video', //=>哈希值
  • search: '?from=qq&lx=stu', //=> 問號傳參[string]
  • query: 'from=qq&lx=stu', //=>問號傳參[string] 不包含問號
  • pathname: '/', //=> 請求資源的路徑名稱
  • path: '/?from=qq&lx=stu', //=>pathname + search
  • href: 'baidu.com/?from=qq&am…' //=> url地址 }
let url = require('url');
console.log(url.parse('http://baidu.com?from=qq&lx=stu#video',true));
// 返回一個url對象
複製代碼

6、http內置模塊

【http內置模塊】

服務器端任務

  • 1.建立服務(指定端口的web服務器)
  • 2.接收客戶端的請求信息,而且進行解析處理,把須要的內容獲取到,而且響應給客戶端

注意:基於node建立後臺程序,咱們通常都建立一個server模塊,在模塊中實現建立web服務,和對於請求的處理(通常會把server模塊放到當前項目的根目錄下)

//導入內置模塊
let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');

//建立web服務 
let port = 80;
let server = http.createServer((req,res)=>{
    /* 當服務建立成功,而且客戶端向當前服務發送了請求才會執行回調函數,而且發送一次請求,回調函數就會觸發執行一次 客戶端如何向建立的服務器發送請求? 對應好協議、域名、端口等信息,在瀏覽器中或者ajax等中發送請求便可 http://localhost:80/... 服務在電腦上,localhost本機域名,也就是本機的客戶端服務器,訪問本機的服務器端程序(也就是本身的電腦既是客戶端又是服務器端) http://內網ip:80/... IP作域名訪問,若是是內網IP,相同局域網下的用戶能夠訪問這個服務,若是是外網IP,全部能聯網的基本上均可以訪問這個服務(局域網下訪問,須要互相關掉防火牆) 查看內網IP:在CMD中輸入ipconfig => 172.18.0.80 localhost:80/ 等同於 172.18.0.80:80/ */ 
    console.log('hello world!');
});

server.listen(port,()=>{
    //回調函數:當服務建立成功,而且端口號也已經監聽成功後,觸發的回調函數
    console.log(`server is success,listen${port}!`); // server is success,listen80!
});//監聽一個端口 [0~65535]
//http.createServer().linten(80);

// 當服務建立成功,命令行中會一直存在光標閃爍,證實服務器正在運行中(必定要保證服務試運行的),ctrl+c => 結束運行服務

複製代碼

1) 關於參數 req和res

兩個參數

    1. req:require 請求對象,包含了客戶端的請求信息(不包括hash值)
    • req.url 存儲的是請求資源的路徑地址以及問號傳參
    • req.method 客戶端請求方式
    • req.headers 客戶端的請求頭信息(是一個對象)
    1. res:response 響應對象,包含了一些屬性和方法,可讓服務器端返回給客戶端內容
    • res.write 基於這個方法,服務器端能夠向客戶端返回內容
    • res.end 結束響應 -res.writeHead 重寫響應頭信息 (是一個對象)
      res.writeHead(200,{
          'content-Type':'text/plain;charset=utf-8'
          // text/plain 純文本類型
      })
      複製代碼
    • res.setHeader 重寫響應頭信息 (不用寫狀態碼) res.setHeader('Content-type','text/html; charset=utf-8');

2) 關於req.url: 把請求的url地址中,路徑名稱 和 問號傳參 分別解析出來

用url模塊中的parse url.parse(req.url)

// 把url中的路徑地址和問號傳參分別解析
let {pathname,query} = url.parse(req.url,true)
console.log(pathname,query);
/* /index.html [Object: null prototype] { uesr: 'tom', name: 'haha' } */
複製代碼
let http = require('http');
let url = require('url');
let path = require('path');
let fs = require('fs');

//建立web服務 
let port = 8080;
// let handle = function handle(req,res){
    
// }
// http.createServer(handle).listen(port);

let server = http.createServer((req,res)=>{
    // console.log(url,method,headers);
    // // 獲取請求頭中某個具體信息
    // console.log(headers['user-agent']);
    /* /?user=tom GET 請求頭:{ host: 'localhost:8080', connection: 'keep-alive', 'upgrade-insecure-requests': '1', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36', accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,;q=0.8,application/signed-exchange;v=b3', 'accept-encoding': 'gzip, deflate, br', 'accept-language': 'zh-CN,zh;q=0.9' } */

    // res.write('hello world!');
    // res.end('hello world!'); //表示服務器端返回字符串內容並結束響應 通常返回的是string或者buffer格式的數據

    //重寫響應頭信息 是一個對象 (中文設置)
    /* 對象有兩個參數 1. HTTP狀態碼 2.'content-Type':'text/plain;charset=utf-8' 解決中文亂碼問題 */
    res.writeHead(200,{
       'content-Type':'text/plain;charset=utf-8'
       // text/plain 純文本類型
    })
    res.end(JSON.stringify({name:'哈哈哈'}));//{"name":"xxx"} 返回JSON格式的字符串
    
});
server.listen(port);

複製代碼

7、關於npm

  • npm -v 查看nom版本號
  • npm install 安裝
  • npm init -y 配置項目清單
    • 會自動生成package.json文件
// package.json文件
{
    "name": "NODE",
    "version": "1.0.0",
    "description": "",
    "main": "server.js",
    "scripts": {
        "server": "node server.js"
    },
    "keywords": [],
    "author": "",
    "license": "ISC"
}
複製代碼

8、get請求 寫接口

<input type="text" id="txt" />

複製代碼
txt.onblur = function () {
    jsonp({
        callback:'cb',
        url:"http://localhost",
        data:{
            user:this.value
        },
        success:function(data){
            console.log(data);
        }
    })
}


function jsonp(json) {
    let opt = {
        callback: 'callback',
        url: '',
        data: {},
    }
    let fnName = json.fname || 'jQuery_' + (Date.now());
    window[fnName] = function (data) {
        json.success(data);
        // delete window[fnName];
        window[fnName] = null;
    }

    //動態建立都異步
    let oS = document.createElement('script');
    // oS.src = json.url + '?' +new URLSearchParams(json.data) + '&'+json.callback+'='+fnName;
    json.data[json.callback] = fnName; //cb=jquery_231231
    oS.src = json.url + '?' + new URLSearchParams(json.data);
    document.querySelector('head').appendChild(oS);
    oS.remove();
}

複製代碼
// 服務器端

//建立服務器
const http = require('http');
//建立服務
let sql = [
    {
        user: 'Tom',
        password: 123
    },
    {
        user: 'Jess',
        password: 1234
    },
    {
        user: 'Alex',
        password: 12345
    }
];
const app = http.createServer((request, response) => {
    let url = request.url; //接受客戶端發送的請求(參數:key=val&key2=val2... 此參數是字符串)
    let obj = {};
    if (url !== '/favicon.ico') {
        // 把url字符串轉化爲對象 把字符串先轉成數組,再把數組轉成對象
        url.split('?').split('&').forEach(item => {
            let ary = item.split('=');
            console.log(ary)
            obj[ary[0]] = ary[1];
        });
        // 判斷數組中是否有發送來的用戶名 
        let isExist = sql.find(e => e.user === obj.user);
        console.log(isExist)
        // 中文設置
        response.setHeader('Content-Type', 'text/html; charset=utf-8');
        // 若是數據數組中有,說明用戶名被佔用
        // obj.cb 是後臺返回給前臺的數據
        if (isExist) {
            response.write(obj.cb + "({code:1,msg:'用戶名已被註冊'})");
        } else {
            response.write(obj.cb + "({code:0,msg:'註冊成功'})");
        }
        response.end();
    }
})
//端口監聽
app.listen(80)
複製代碼

9、post請求 寫接口

fetch('/post',{
    body:'user=xiaoqiang',
    method:'post',
    headers:{
        'Content-Type':'application/x-www-form-urlencoded'
    }
    }).then(e=>e.json())
    .then(d=>{
    console.log(d);
});

複製代碼
// 服務器端
const http = require('http');
const fs = require('fs');
const querystring = require('querystring');
// const 

let sql = ['zhiqiang']
http.createServer((req,res)=>{
    let url = req.url;
    if(url !== '/favicon.ico'){
        //走文件
        if(url.includes('.html')){
            try {
                let d = fs.readFileSync('./www'+url);
                res.write(d.toString());
            } catch (error) {
                let er = fs.readFileSync('./www/404.html');
                res.write(er.toString());
            }
            res.end();
        }else{
            //走接口

            if(url === '/post'){
                let str = '';
                req.on('data',(d)=>{
                    // console.log(d.toString())
                    str += d;
                });

                req.on('end',()=>{
                    // console.log(str.toString(),111);
                    let obj = querystring.parse(str);
                    // console.log(.user)
                    res.setHeader('Content-Type','text/html;charset=utf-8');
                    if(sql.includes(obj.user)){
                        res.write(JSON.stringify({code:0,msg:"失敗"}));
                    }else{
                        res.write(JSON.stringify({code:1,msg:"成功"}));
                    }
                    res.end();
                });
            }
        }
    }
    
}).listen(80);



複製代碼

====

服務器上有一堆項目代碼,這堆項目代碼中既可能有服務器端的程序代碼,也可能有客戶端的程序代碼,而客戶端的程序代碼咱們通常放到static(靜態的)這個文件夾當中

static/publice: 都是服務器端須要返回給客戶端,有客戶端瀏覽器渲染和解析的(前端項目:包括頁面、css、js、圖片等)

server.js: 都是須要在服務器端基於node執行的(後端項目:通常只有js)

相關文章
相關標籤/搜索