日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Node — 第四天(Promise与路由)

發布時間:2023/12/13 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Node — 第四天(Promise与路由) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Promise - ES6新對象

Promise能夠處理異步程序。

回調地獄

JS中或node中,都大量的使用了回調函數進行異步操作,而異步操作什么時候返回結果是不可控的,如果我們希望幾個異步請求按照順序來執行,那么就需要將這些異步操作嵌套起來,嵌套的層數特別多,就叫做回調地獄。

下面的案例就有回調地獄的意思:

案例:有 a.txt、b.txt、c.txt三個文件,使用fs模板按照順序來讀取里面的內容,代碼:

// 將讀取的a、b、c里面的內容,按照順序輸出 const fs = require('fs');// 讀取a文件 fs.readFile('./a.txt', 'utf-8', (err, data) => {if (err) throw err;console.log(data.length);// 讀取b文件fs.readFile('./b.txt', 'utf-8', (err, data) => {if (err) throw err;console.log(data);// 讀取c文件fs.readFile('./c.txt', 'utf-8', (err, data) => {if (err) throw err;console.log(data);});}); });

案例中,只有三個文件,試想如果需要按照順序讀取的文件非常多,那么嵌套的代碼將會多的可怕,這就是回調地獄的意思。

Promise簡介

  • Promise對象可以解決回調地獄的問題
  • Promise 是異步編程的一種解決方案,比傳統的解決方案(回調函數和事件)更合理和更強大
  • Promise可以理解為一個容器,里面可以編寫異步程序的代碼
  • 從語法上說,Promise 是一個對象,使用的使用需要 new

Promise簡單使用

Promise是“承諾”的意思,實例中,它里面的異步操作就相當于一個承諾,而承諾就會有兩種結果,要么完成了承諾的內容,要么失敗。

所以,使用Promise,分為兩大部分,首先是有一個承諾(異步操作),然后再兌現結果。

第一部分:定義“承諾”

// 實例化一個Promise,表示定義一個容器,需要給它傳遞一個函數作為參數,而該函數又有兩個形參,通常用resolve和reject來表示。該函數里面可以寫異步請求的代碼 // 換個角度,也可以理解為定下了一個承諾 let p = new Promise((resolve, reject) => {// 形參resolve,單詞意思是 完成// 形參reject ,單詞意思是 失敗fs.readFile('./a.txt', 'utf-8', (err, data) => {if (err) {// 失敗,就告訴別人,承諾失敗了reject(err);} else {// 成功,就告訴別人,承諾實現了resolve(data.length);} }); });

第二部分:獲取“承諾”的結果

// 通過調用 p 的then方法,可以獲取到上述 “承諾” 的結果 // then方法有兩個函數類型的參數,參數1表示承諾成功時調用的函數,參數2可選,表示承諾失敗時執行的函數 p.then((data) => {},(err) => {} );

完整的代碼:

const fs = require('fs'); // promise 承諾// 使用Promise分為兩大部分// 1. 定義一個承諾 let p = new Promise((resolve, reject) => {// resolve -- 解決,完成了; 是一個函數// reject -- 拒絕,失敗了; 是一個函數// 異步操作的代碼,它就是一個承諾fs.readFile('./a.txt', 'utf-8', (err, data) => {if (err) {reject(err);} else {resolve(data.length);}}); });// 2. 兌現承諾 // p.then( // (data) => {}, // 函數類似的參數,用于獲取承諾成功后的數據 // (err) => {} // 函數類型的參數,用于或承諾失敗后的錯誤信息 // ); p.then((data) => {console.log(data);},(err) => {console.log(err);} );

then方法的鏈式調用

  • 前一個then里面返回的字符串,會被下一個then方法接收到。但是沒有意義;

  • 前一個then里面返回的Promise對象,并且調用resolve的時候傳遞了數據,數據會被下一個then接收到

  • 前一個then里面如果沒有調用resolve,則后續的then不會接收到任何值

    const fs = require('fs'); // promise 承諾new Promise((resolve, reject) => {fs.readFile('./a.txt', 'utf-8', (err, data) => {err ? reject(err) : resolve(data.length);}); }) .then((a) => {console.log(a);return new Promise((resolve, reject) => {fs.readFile('./a.txt', 'utf-8', (err, data) => {err ? reject(err) : resolve(data.length);});}); }) .then((b) => {console.log(b);return new Promise((resolve, reject) => {fs.readFile('./a.txt', 'utf-8', (err, data) => {err ? reject(err) : resolve(data.length);});}); }) .then((c) => {console.log(c) }) .catch((err) => {console.log(err); });

    catch 方法可以統一獲取錯誤信息

封裝按順序異步讀取文件的函數

function myReadFile(path) {return new Promise((resolve, reject) => {fs.readFile(path, 'utf-8', (err, data) => {err ? reject(err) : resolve(data.length);})}); }myReadFile('./a.txt') .then((a) => {console.log(a);return myReadFile('./b.txt'); }) .then((b) => {console.log(b);return myReadFile('./c.txt'); }) .then((c) => {console.log(c) }) .catch((err) => {console.log(err); });

async 和 await 修飾符

ES6 — ES2015

async 和 await 是 ES2017 中提出來的。

異步操作是 JavaScript 編程的麻煩事,麻煩到一直有人提出各種各樣的方案,試圖解決這個問題。

從最早的回調函數,到 Promise 對象,再到 Generator 函數,每次都有所改進,但又讓人覺得不徹底。它們都有額外的復雜性,都需要理解抽象的底層運行機制。

異步I/O不就是讀取一個文件嗎,干嘛要搞得這么復雜?異步編程的最高境界,就是根本不用關心它是不是異步。

async 函數就是隧道盡頭的亮光,很多人認為它是異步操作的終極解決方案。

ES2017提供了async和await關鍵字。await和async關鍵詞能夠將異步請求的結果以返回值的方式返回給我們。

  • async 用于修飾一個 function
  • async 修飾的函數,表示該函數里面有異步操作(Promise的調用)
  • await和async需要配合使用,沒有async修飾的函數中使用await是沒有意義的,會報錯
  • await需要定義在async函數內部,await后面跟的一般都是一個函數(函數里面包含有Promise)的調用
  • await修飾的異步操作,可以使用返回值的方式去接收異步操作的結果
  • 如果有哪一個await操作出錯了,會中斷async函數的執行

總結來說:async 表示函數里有異步操作,await 表示緊跟在后面的表達式需要等待結果

const fs = require('fs'); // 將異步讀取文件的代碼封裝 function myReadFile (path) {return new Promise((resolve, reject) => {fs.readFile(path, 'utf-8', (err, data) => {err ? reject(err) : resolve(data.length);});}) }async function abc () {let a = await myReadFile('./a.txt');let b = await myReadFile('./b.txt');let c = await myReadFile('./c.txt');console.log(b);console.log(a);console.log(c); }abc();

路由

什么是路由

廣義上來講,路由就是映射關系

程序中的路徑也是映射關系:

Express 中的路由

在 Express 中,路由指的是客戶端的請求與服務器處理函數之間的映射關系。
Express 中的路由分 3 部分組成,分別是請求的類型、請求的 URL 地址、處理函數,格式如下

// 路徑 ,就是我們之前說的接口的處理程序 app.get('/api/getbooks', (req, res) => {});app.post('/api/addbook', (req, res) => {});

每當一個請求到達服務器之后,需要先經過路由的匹配,只有匹配成功之后,才會調用對應的處理函數。

在匹配時,會按照路由的順序進行匹配,如果請求類型和請求的 URL 同時匹配成功,則 Express 會將這次請求,轉 交給對應的 function 函數進行處理。

模塊化路由

為了方便對路由進行模塊化的管理,Express 不建議將路由直接掛載到 app 上,而是推薦將路由抽離為單獨的模塊。 將路由抽離為單獨模塊的步驟如下:

  • 創建路由模塊對應的 .js 文件

  • 創建router/login.js 存放 登錄、注冊、驗證碼三個路由
  • 創建router/heroes.js 存放 和英雄相關的所有路由
  • 調用 express.Router() 函數創建路由對象

    const express = require('express'); const router = express.Router();
  • 向路由對象上掛載具體的路由

    // 把app換成router,比如 router.get('/xxx/xxx', (req, res) => {}); router.post('/xxx/xxx', (req, res) => {});
  • 使用 module.exports 向外共享路由對象

    module.exports = router;
  • 使用 app.use() 函數注冊路由模塊 – app.js

    // app.js 中,將路由導入,注冊成中間件 const login = require('./router/logon.js'); app.use(login)// app.use(require('./router/heroes.js')); app.use( require(path.join(__dirname, 'router', 'heores.js')) );
  • 為路由模塊添加前綴

    我們可以省略路由模塊中的 /api 前綴,而是在注冊中間件的時候,統一設置。

    app.use('/api', router);

    具體:

    app.js中:

    // 導入路由模塊,并注冊成中間件 app.use('/api', require(path.join(__dirname, 'router', 'login.js')) ); app.use('/my', require(path.join(__dirname, 'router', 'heroes.js')) );

    路由文件中,把前綴 /api 和 /my 去掉

    使用路由模塊的好處

    • 分模塊管理路徑,提高了代碼的可讀性
    • 可維護性更強
    • 減少路由的匹配次數
    • 權限管理更方便
    • etc…

    總結

    以上是生活随笔為你收集整理的Node — 第四天(Promise与路由)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。