後端知識點總結——NODE.JS(高階)

楷楷發表於2019-02-16

後端知識點總結——NODE.JS(高階)

1.Node入門:

什麼是: 針對網路應用開發的平臺
主要特徵:

  1. 基於Google的JavaScript執行時引擎V8
  2. 擴充套件了Node標準類庫: TCP,同步或非同步檔案管理,HTTP

為什麼使用Node:

  1. 可以在伺服器端執行js: 現有前端團隊可直接參與後端js開發
  2. js天生支援非阻塞IO:
    IO: 代表一切資料進出程式的操作:
    包括: 檔案讀寫, 資料庫操作, 網路操作
    問題: 有延遲
    傳統阻塞IO: IO操作會阻塞當前主執行緒,直到本次IO操作完成,才能執行後續程式碼。
    非阻塞IO: 即使處理較慢的IO操作時,主進城仍然能處理其他請求
    Js天生支援非阻塞: 回撥函式=事件迴圈+回撥佇列
    所有非阻塞的操作,返回的結果暫時在回撥佇列中等待
    由事件迴圈,自動依次取回到主程式中恢復執行
    回撥佇列在主程式之外儲存回撥函式,所以,不會干擾主程式執行
    非阻塞在Web伺服器中:
    普通伺服器端應用: 雖然可實現每個請求獨立執行緒/程式, 但如果一個請求中,包含多個阻塞IO操作(訪問資料庫,網路,讀寫硬碟檔案),該請求返回的時間就等於所有IO操作的時間總和——慢
    Node伺服器端應用: 不但每個請求是一個獨立的執行緒,且,每個請求內的每個IO操作,都是非阻塞的。

    一個包含多個IO操作的請求,返回的總響應時間,僅僅等於其中一個時間最長的IO操作的時間。
    Node.js vs javascript: 
    Javascript: 程式語言, 依照ECMAScript

    2種執行環境:

    1. 客戶端瀏覽器: 由各種客戶端瀏覽器中的js直譯器執行
      擴充套件: DOM API 和 BOM API 主要目的是為了操作網頁內容和瀏覽器視窗
    2. 獨立的js直譯器:Node.js 應用程式開發和執行的平臺
      僅支援ECMAScript
      擴充套件: 各種專門的伺服器模組: TCP, HTTP, 檔案讀寫, MYSQL

      構建一個簡單的node應用:
      建立一個新的node專案: 基本命令:
      mkdir 專案資料夾
      cd 專案資料夾
      npm init //負責在當前所在的專案目錄下自動生成package.json配置檔案
      執行:node 入口檔案.js

2.module

Node應用都是由模組組成
模組就是組織程式功能的一種檔案或資料夾
Node應用採用CommonJS模組規範
CommonJS規定:

  1. 每個檔案就是一個模組,有自己的作用域——避免全域性汙染
    一個檔案內定義的變數,函式,類都是該檔案私有,對其它檔案預設不可見
  2. 物件,方法和變數也可以從一個檔案/模組中匯出(exports),用在其它檔案/模組中。

實際專案中,都是將各種功能/資料,劃分為不同專案模組來管理
如何定義一個模組:2步:

  1. 在模組/檔案中定義業務程式碼(物件,class,函式)
  2. 將內部的功能丟擲,用於將來其它js檔案呼叫

2種情況:

2.1物件導向的方式:

  1. 定義一種class或一個物件,包裹屬性和功能
  2. 將class或物件直接賦值給module.exports
    其中: module,指當前模組物件/當前檔案

       exports是當前module物件的一個屬性
         本質上也是一個物件,儲存將來要丟擲的所有東西
         exports是當前模組對外的唯一介面

    今後,只要希望將模組內部的東西,丟擲到外部,供其它檔案使用時,都要新增到module.exports上
    其它檔案要想使用當前模組的功能,就必須用require引入當前模組,而require的本質是找模組的exports.

2.2面向函式的方式:

  1. 在檔案中,定義多個零散的方法
  2. 將多個零散的方法新增到module的exports上
    其實,可先將零散的方法,先集中定義在一個物件中,再將整個物件賦值給module.exports屬性

引入模組: require() 專門負責載入模組檔案
何時: 只要在另一個js檔案中,引入自定義模組並獲取內容時,都用require
本質: 找到js檔案,並執行,返回module.exports物件
優化: 單例模式singleton: 始終保持專案中只有一個物件的例項

模組的引入和載入也是單例模式: 模組只在第一次被require時,建立。之後,快取在記憶體中。反覆require不會導致反覆建立模組物件。

強調: 模組是同步載入:前一個載入完,後一個才能開始

 強烈建議: 所有require必須集中在頂部

路徑: 以./開頭,表示使用相對路徑,相對於當前正在執行指令碼所在路徑——不能省略!

    以/開頭,表示Linux系統根目錄——絕對路徑
    以自定義變數開頭,表示在變數儲存的地址下繼續查詢
    什麼字首也不加!只寫模組名: 表示載入一個核心模組或專案引入的第三方模組
      路徑查詢順序:
        /usr/local/lib/node/模組名.js
        /home/user/projects/node_modules/模組名.js
        /home/user/node_modules/模組名.js
        /home/node_modules/模組名.js
        /node_modules/模組名.js

坑: 簡寫: module.exports.fun=function(){…}

       可簡寫為: exports.fun=function(){…}
   exports其實是module.exports的別名
   var exports=module.exports;
問題: 給exports賦值,無法賦值給module.exports
   因為exports只是一個變數,臨時儲存module.exports的地址值。再次給exports賦任何新值,都導致exports與module.exports分道揚鑣!
避免: 不要用簡寫exports

3.目錄模組:

何時: 當一個模組程式碼,複雜到需要進一步細分時,一個模組,就可能由多個檔案組成,儲存在一個資料夾裡。
如何:

  1. 建立資料夾,集中儲存相關的多個js檔案模組
  2. 在資料夾中新增一個主模組(index.js),主模組中,引入並組織好多個小模組一起匯出
  3. 在資料夾中新增package.json檔案,其中:

      {
        "name":"模組名",
        "main":"./主模組相對路徑"
      }
    

    其實, 如果沒有main甚至沒有package.json,也行。
    會自動優先找資料夾下的index.js

引入目錄模組: require(“./目錄名”)
如果希望直接用目錄名引用模組,不加相對路徑:
將目錄放入node_modules資料夾中

npm: 第三方模組的包管理工具: 查詢,下載
除了核心模組和自定義本地模組,node生態系統還提供了大量優質第三方模組
如何:
查詢模組:

模糊查詢: npm search 模組名
精確查詢: npm search /^模組名$/
  如果現實完整描述: npm search /^模組名$/ --parseable

安裝模組: 2個位置:

    1. 全域性安裝: npm install -g 模組名
      路徑: Linux: /usr/local/lib/node_modules

         Windows:
          C:Users使用者名稱AppDataRoaming
      pm
      ode_modules
    2. 專案本地安裝: npm install 模組名 -save
    1. 全域性物件:
      全域性作用域物件不是window,而是global
      ECMAScript標準中原本規定的就是global
      在瀏覽器中被window代替
      強調: 互動模式: 直接在命令列中測試node應用,所有全域性變數/全域性函式自動成為global的成員

       指令碼模式: 通過載入js檔案執行node應用,檔案內的"全域性變數/全域性函式",僅當前檔案所有,不會成為global的成員——避免了全域性汙染
      

      console物件:
      測試重要手段: 打樁: 在關鍵位置輸出關鍵變數的值
      輸出文字資訊: 瀏覽器中4種輸出,node中合併為2中:
      console.log/info() 輸出普通的文字資訊
      console.error/warn() 輸出錯誤資訊
      其實: console.xxx()都自帶格式化功能
      Console.log vs console.error: .error可直接匯出到檔案日誌中

      如何: node xxx.js 2> error-file.log
      其中:2>表示輸出流,專門向硬碟檔案寫入內容

      輸出耗時:
      Console.time(“標籤”); //預備,開始!
      正常程式邏輯
      Console.timeEnd(“標籤”); //完成! 自動輸出與time之間的時間間隔
      單元測試:
      什麼是: 對程式中最小的執行單元進行測試
      開發人員主動對自己的函式執行單元測試
      如何: console.assert(判斷條件, “錯誤提示”)

                     只有條件不滿足時,才輸出msg

      輸出堆疊:
      console.trace()

    1. 全域性物件: process:

    process.platform
    process.pid
    process.kill(pid);
    

    控制檯輸入輸出:
    2步:

    1. 讓控制檯進入輸入狀態:

    process.stdin.resume()
    process.stdin.setEncoding(“utf-8”)

    1. 監聽stdin的data事件:
      在控制檯輸入後,按回車,會觸發stdin的data事件
      process.stdin.on("data",text=>{
          process.stdout.write( … text … )
        })
    

    控制檯引數:
    2步: 1. 定義關聯陣列,儲存引數名和引數對應的處理函式

    2. 啟動時, process.argv陣列可自動獲得傳入的所有引數,  根據引數呼叫不同的處理函式

    process.argv: [“node.exe”,”xxx.js”,”引數值1″,”引數值2″,…]

    高精度計時:
    精確到納秒, 優點: 不受系統時間影響
    如何: 2步: 1. 獲得開始的時間戳: var start=process.hrtime();

          2. 獲得結束時間戳: var diff=process.hrtime(start);

    diff: [秒數, 納秒]

    獲得秒差: diff[0]+diff[1]/1e9
    獲得毫秒差: diff[0]*1000+diff[1]/1e6

    Vs console.time/timeEnd:
    time/timeEnd: 缺: 精度低, 優: 效率高
    hrtime: 優: 精度高,且不受系統時間影響

          缺點: 效率低
    

    非I/O的非同步操作(定時器):
    何時: 要執行非同步回撥時
    如何:

    1. setTimeout/setInterval() 將回撥函式新增到事件迴圈的timer階段的佇列中等待執行。
      Timer階段是事件迴圈的第一階段
      習慣上: setTimeout往往都會設定ms數
    2. setImmediate() 將回撥函式新增到事件迴圈的check階段的佇列中等待執行。
      Check階段比Timer要晚執行
      習慣上: 並不設定毫秒數,而是普通的追加到等待佇列末尾即可。
    3. process.nextTick() 將回撥函式加入nextTickQueue佇列等待執行
      nextTickQueue不參與事件迴圈,而是在開始timer之前,就立刻執行nextTickQueue中的回撥函式
      優點: 不會有延遲
    4. 自定義的EventEmiter

    5.EventEmitter型別:

    Node.js所有非同步I/O操作完成時,都會傳送一個事件到事件佇列
    Node.js中許多物件都會觸發事件:
    比如: http模組: 建立Server物件,監聽http請求

       一旦收到一個http請求,則立刻觸發事件,將處理函式放入事件佇列
      fs模組: 在每次讀寫完檔案時,也會觸發事件,將處理函式放入事件佇列

    什麼是EventEmitter: 專門封裝事件監聽和事件觸發的API的一種型別
    所有可以觸發事件的物件,都是EventEmitter型別的子物件
    如何讓一個物件可以監聽並觸發事件:

    1. 引入events模組: const events=require(“events”)
    2. 建立events.EventEmitter型別的子物件:
      var emitter=new events.EventEmitter();
    3. 用on,為物件新增事件監聽:
      emitter.on(“自定義事件名”,function 處理函式(引數列表){

      … 獲得引數, 執行操作 …

      })

    4. 在任何情況下,使用物件的emit方法,觸發指定的事件:
      emitter.emit(“自定義事件名”,引數值,…)

    觸發一次後,自動解綁:
    emitter.once(“自定義事件名”,處理函式)

    錯誤處理:
    問題: try catch無法捕獲非同步呼叫中的錯誤
    解決: Domain
    何時: 只要既希望捕獲主程式錯誤,又希望捕獲非同步操作的錯誤時
    如何:

    1. 引入domain模組: const domain=require(“domain”)
    2. 建立domain物件: const mpDomain=domain.create();
    3. 為domain物件新增error事件監聽
      mpDomain.on(“error”,err=>{

      console.log("出錯啦!"+err);

      })

    4. 將可能出錯的程式放入mpDomain中執行:
      mpDomain.run(()=>{

      musicPlayer.emit("play");

      })

    6.協議:

    什麼是: 計算機之間通過網路實現通訊時,事先達成的一種”約定”
    為什麼: 約定使不同廠商的裝置,不同作業系統之間,都可按照統一約定,任意通訊

    7.分組交換方式:

    什麼是: 將大資料分割為一個個叫做包(packet)的較小單元進行傳輸

    8.ISO/OSI模型:

    ISO(國際標準化組織)
    OSI(開放式通訊系統互聯參考模型)
    7層:

    1. 應用層: 規定應用程式中的通訊細節
      包括: HTTP FTP TELNET SMTP DNS
    2. 表示層: 負責資料格式的轉換
    3. 會話層: 建立連線
    4. 傳輸層: 控制總體資料傳輸
      包括:
      TCP(傳輸控制協議): 可靠傳輸
      優: 可靠,客戶端和服務端可雙向通訊
      缺: 傳輸效率低
      何時: 要求可靠性時
      UDP(使用者資料包協議):
      何時: 對可靠性要求不高,對傳輸效率要求高,且傳送小資料(qq, 微信, 線上視訊播放)
    5. 網路層: 將資料分組傳輸到目的地
    6. 資料鏈路層: 負責規劃網路中節點間的路線
    7. 物理層: 負責通過乙太網,藍芽,光纖傳送0/1的位元流

    9.TCP/IP: 網際網路協議套件

    包含: TCP 傳輸控制協議

       IP 網際網路協議

    TCP/IP不是ISO標準
    TCP/IP 只有四層:

    鄙視:

    1. TCP/IP四層協議,分別對應ISO/OSI中的哪一層: 圖6
    2. 網路建立連線需要3次握手,斷開連線需要4次握手,分別是:
      圖7
    3. HTTP/1.0 1.1 2.0每次升級有哪些不同

    10.net模組:

    使用net模組:

    1. 可建立基於TCP的客戶端與伺服器端通訊

    建立TCP伺服器:
    引入net模組
    使用net.createServer方法建立服務端物件server

    接受一個回撥函式作為引數:
     只要有客戶端連線到當前服務端,就自動執行該回撥函式
     回撥函式接受一個socket引數物件,用於與客戶端通訊
     Socket物件: 是客戶端在伺服器端的一個代理物件
                可通過socket和真正的客戶端傳送和接受訊息
     Socket物件的data事件,可監聽客戶端發來的訊息
       回撥函式中, data引數為訊息的內容
     Socket物件的end事件,可監聽客戶端的斷開
     Socket的write方法向客戶端輸出訊息

    呼叫server的listen方法,繫結到一個埠,監聽客戶端發來的連結請求

    也接受一個回撥函式引數,但僅在啟動監聽後執行一次

    建立TCP客戶端:
    引入net模組
    使用net.connect()方法向伺服器建立連線
    var client=net.connect(服務端埠,ip,function(){})
    回撥函式在連線建立後,自動觸發一次
    為client的data事件繫結處理函式,處理函式的data引數自動接收服務端發來的訊息
    為client的end事件新增處理函式,當客戶端斷開連線時執行操作
    在任何位置可用client.write(“訊息內容”)向服務端傳送
    在任何位置可用client.end() 斷開與服務端連線

    11.HTTP模組:

    使用HTTP模組:

    1. 實現WEB伺服器,接受請求並返回響應(代替了apache,tomcat)
    2. 模擬客戶端向一個指定的WEB伺服器傳送請求

    建立HTTP服務端:
    引入HTTP模組
    建立HTTP服務端server:
    var server=http.createServer(function(req,res){

     //只要有請求傳送到該伺服器,就自動觸發該回撥函式
     //其中: 
       //req物件,封裝了發來的請求資訊
       //res物件,專門用於向伺服器端返回響應
        //res.writeHead(狀態碼,{ 屬性:值, …:… ,…})
        //res.write("放入響應主體中")
        //res.end()

    })
    啟動監聽: server.listen(埠,function(){ … })

    建立HTTP請求:
    使用http.request()方法建立一個請求(連線),獲得請求物件req
    接收2個引數:

    options物件引數:
     host
     port
     method
     path  /index.html?page=12
    回撥函式: 在伺服器端返回響應時執行
     引數res: 專門用於獲得響應內容(響應頭和響應主體)
      HTTP協議規定: 先發響應頭部 用res.headers獲得響應頭部物件,用res.statusCode 獲得狀態碼
      強調: 響應主題是稍後才傳送過來
       必須用res.on("data",function(buffer){ … String(buffer) …})
      強調: 凡是從響應中獲得的data,預設都是字串

    req.end()結束併傳送請求。
    強調:必須加req.end(),請求才能傳送出去

    http.get()
    專門向伺服器端傳送get請求
    是http.request()的簡化:

    1. 自動設定method為get;
    2. 自動調req.end

    但依然需要使用res.on(“data”,function(buffer){ … })來接受響應主體

    分塊:
    問題: 如果響應主體過大,一次性傳不過來
    解決:

       分塊傳送和接受,再拼接,再整體轉換
       如果分塊接受,res.on("data",function(buf){ … })每收到一塊,就會反覆觸發。
       其中buf,僅是其中一塊而已
    

    請求檔案,儲存在本地:
    引入fs模組:
    建立寫入流,指向目標檔案: var writable=fs.createWriteStream(“相對路徑”)
    使用管道,將寫入流writable連線到res物件上: res.pipe(writable)

    響應頭部: res.writeHead(狀態碼,{ })
    允許跨域: “Access-Control-Allow-Origin”:”請求來源的網站”
    指定內容型別:”Content-Type”:”application/json” “text/css”

    req物件:
    請求頭部: req.headers
    請求方法: req.method
    請求地址: req.url
    url的處理:

    引入url模組
    用url.parse(req.url,true)將req.url字串轉為物件
     其中true,表示將search中的引數也轉為物件屬性
     如何: var obj=url.parse(req.url, true)
      其中: obj.query中儲存了所有引數及其值

    獲得請求引數:
    Get: get方式的引數都通過url中的search傳遞

      obj=url.parse(req.url,true)
      obj.query

    Post: post方式的引數都是放在請求主體中,沒有在url中

      問題:obj.query無法獲得
      解決: req.on("data",function(buf){ … })
      問題: String(buf)獲得的是引數的字串
      解決: querystring模組
    
    
    

    12.https模組:

    問題: http協議是明文的
    危害: 1. 通訊使用明文,內容可能被竊聽

       2. 不驗證身份,有可能遭遇偽裝
       3. 無法證明訊息的完整性,訊息有可能被篡改

    網路嗅探器:

    13.解決: https協議

    https是更安全的http協議:

    1. 客戶端和伺服器端的雙向認證
    2. 完整性檢查
    3. 內容加密

    https=http+ssl

    ssl/tls: ssl 安全套接層,對傳統socket進一步提供安全的保護

     tls 傳輸層安全, 其實是ssl的繼任者
    

    14.提供三大服務:

    1. 客戶端和伺服器端的雙向認證 ——可靠
    2. 完整性檢查 ——完整
    3. 資料加密 ——機密性
      tls/ssl的執行過程:

    15.Step0: 獲得伺服器端證照, 3步:

    1. 在伺服器端生成私鑰
    2. 用私鑰生成一個證照申請檔案
    3. 將私鑰和申請檔案交給第三方CA,第三方CA經過審查,會生成並頒發證照給申請的伺服器
      證照包含2樣東西: 公鑰+公司的資訊
      Step1: 客戶端請求https協議的web伺服器
      Step2: 伺服器返回證照給客戶端
      Step3: 客戶端拿到證照後,將證照交給CA。

        客戶端利用CA中的公鑰隨機生成自己的私鑰
        將私鑰發給伺服器端

      Step4: 伺服器端獲得客戶端發來的客戶端私鑰
      到此,客戶端和伺服器端,擁有了相同的兩個鑰匙
      之後,伺服器和客戶端傳送的所有訊息,都用兩個相同的私鑰加密和解密

    16.如何實現https的web伺服器應用:

    1. 申請https網站的認證證照:

    Step1: 用openssl生成伺服器端私鑰:
    openssl genrsa -out d:/privatekey.pem 1024
    Step2: 用私鑰生成證照申請檔案:

    openssl  req  -new  -key  d:/privatekey.pem  -out  d:/certificaterequest.csr

    Step3: 用私鑰和證照申請檔案共同生成證照檔案

    openssl  x509  -req  -in  d:/certificaterequest.csr  -signkey  
    d:/privatekey.pem   -out  d:/certificate.pem
    

    2.使用node的https模組建立伺服器
    Step1: 引入必須的模組:
    const https=require(“https”);
    const fs=require(“fs”);
    Step2:讀取伺服器私鑰和證照檔案,儲存到伺服器程式的變數中
    let privatekey=fs.readFileSync(“d:/privatekey.pem”);
    let certificate=fs.readFileSync(“d:/certificate.pem”);
    Step3: 用https建立伺服器端應用程式,提供私鑰和證照,並定義處理請求的回撥函式

    https.createServer(
      {
        key: privatekey,
        cert: certificate
    },
    (req,res)=>{
      res.write(“…”)
      res.end();
    }
    ).listen(443)
    

    3.用https模組向https的伺服器傳送請求
    錯誤: http模組不支援向https伺服器傳送請求
    正確:

    var https=require(“https”);
    https.get(“https://…”, res=>{
    res.on(“data”,buf=>{
    buf…
    })
    })

    17.express

    什麼是: 基於node的http模組和第三方的Connect框架的web框架
    Connect框架: 專門將各種各樣的中介軟體函式粘合在一起,共同處理http請求中的req物件
    何時: 只要對req物件反覆執行多種操作時,都要用connect組織多箇中介軟體。
    如何:

    Step1: 安裝connect模組: npm install connect –save

    Step2: 引入connect模組: var connect=require(“connect”)

    Step3: 用connect模組建立處理req物件的應用程式例項var app=connect();

    Step4: 向connect模組的應用程式例項中新增中介軟體函式

      app.use(function md1(req,res,next){
      //加工req物件
      … …
      next();
    })
    

    Step5: connect的應用程式例項,必須要放入createServer中用於處理伺服器接收到的req物件
    http.createServer(app)
    總結: express是在connect基礎上的進一步封裝和簡化,所以express也是採用中介軟體組合的方式,處理req物件
    安裝express框架: 2種:

    1. 使用本地express模組,進能夠提供服務支援,需要自定義新增複雜的程式結構

      Step1: npm install –save express
      Step2: 引入http和express
      const http=require(“http”);
      const express=require(“express”);
      Step3: 建立express應用例項物件:
      let app=express();
      Step4: 為app新增各種處理中介軟體函式
      app.use(function md(req,res,next){ … …})
      Step5: 將app和createServer相連
      http.createServer(app).listen(埠號);

    2. 使用腳手架, 簡化生成專案的結構:

    Step1: 全域性安裝express生成器:
    npm install –g express-generator

    Step2: 用生成器,生成專案腳手架程式碼:
    express 專案資料夾名 –e //-e 表示用EJS作為前端頁面模板
    強調: 只負責生成專案程式碼,並不負責下載依賴包

    Step3: 為腳手架程式碼下載所有依賴包
    cd 專案資料夾下
    npm install //根據package.json中的依賴項

    Step4: 用腳手架程式碼啟動nodejs伺服器端應用程式: npm start

    express專案結構:

    1. ./bin/www.js express專案的啟動檔案

    package.json中: npm start 時 自動執行 node ./bin/www

    2./app.js 對express框架的例項物件的配置
    要求: 對express例項物件app的所有配置必須放在一個獨立的檔案模組app.js中
    然後,在主程式www.js中引入app.js模組

    3../routes/xxx.js 路由模組
    每個子功能,都應該集中定義在一個路由模組檔案中
    在app.js中引入路由檔案模組,並將路由檔案模組新增到app的中介軟體列表中,並設定上級路徑
    在每個子路由模組檔案中,建立路由物件,為路由物件新增不同請求方法和不同子路徑下的處理函式
    強調: 子路由中的相對路徑,都是在上級路徑之下的相對路徑

    改造腳手架專案結構:

    1. 補充缺失的模組:
      express-session 讓express可以處理session
      connect-flash 強化自動維護session的功能
      passport 綜合的使用者驗證解決方案

               ( 使用passport模組,實現qq,微信登入)
    2. 在app.js中新增對新模組的引用:
    3. 為專案新增mongodb支援

    Step1: 安裝mongoose模組和promise模組
    mongoose: node js專用的簡化操作mongodb資料庫的模組

    Step2: 建立資料夾./config,在資料夾下新增config.js
    在config.js中定義物件模組,儲存連線字串
    module.exports={
    db:”mongodb://主機名或ip/資料庫名”}

    Step3: 在./config資料夾下建立mongoose.js,儲存建立連線物件的程式碼:
    var config=require(`./config`),
    mongoose=require(`mongoose`);
    設定mongoose的promise屬性,使用當前專案的promise模組
    mongoose.Promise=require(‘promise’);
    var db=mongoose.connect(config.db) module.exports=db;

    Step4: 根據業務需要,定義mongoose模型物件:
    建立./models資料夾, 在models內為每種業務物件建立專門的模型檔案

    3步:

    1. 引入mongoose,獲得Schema型別
    2. 用Schema建立UserSchema結構
    3. 將UserSchema編譯為User模型,並丟擲為User模組
      Step5: 回到mongoose.js中,在connect之後,引入User模組require(`../models/user.model`);
      Step6: 回到app.js中,在路由中介軟體之前,先請求並初始化mongoose.jsrequire(“./config/mongoose”);

    相關文章