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 上,而是推薦將路由抽離為單獨的模塊。 將路由抽離為單獨模塊的步驟如下:

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

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

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

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

    module.exports = router;
    
  5. 使用 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…

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/247994.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/247994.shtml
英文地址,請注明出處:http://en.pswp.cn/news/247994.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

xcode8 升級后注釋快捷鍵不能使用的解決方法

一種說法: 這個是因為蘋果解決xcode ghost。把插件屏蔽了。解決方法 命令運行: sudo /usr/libexec/xpccachectl 然后必須重啟電腦后生效 還有一種說法:不用指令直接重啟就可以了。

winform datagridview控件使用

最近做項目時&#xff0c;顯示查詢結果總需要綁定到datagridview控件上顯示&#xff0c;總結了給datagridview綁定數據的方式&#xff0c;以及導出datagridview數據到excel表格&#xff0c;如有錯誤請多指教 1.直接綁定數據源&#xff0c;可以綁定的數據格式有List<T>,Da…

Node — 第五天

1. MySQL數據庫 phpstudy 數據庫服務器及圖形化軟件 軟件鏈接 鏈接&#xff1a;https://pan.baidu.com/s/1F8wdoMstHAJkINfDKDejsw 提取碼&#xff1a;xl3k 數據庫對于我們前端同學來說&#xff0c;就是一個了解。 對于不會變化的數據&#xff08;省、市、縣&#xff09;&…

iOS10 權限訪問崩潰

手機升級了 iOS10 Beta&#xff0c;然后用正在開發的項目 裝了個ipa包&#xff0c;發現點擊有關 權限訪問 直接Crash了&#xff0c;并在控制臺輸出了一些信息&#xff1a; This app has crashed because it attempted to access privacy-sensitive data without a usage descr…

Node — 第六天(前后端分離)及(身份驗證)

綜合應用服務端知識點搭建項目 下載安裝所需的第三方模塊 npm init -y npm i express cors mysql # express 用于搭建服務器 # cors 用于解決跨域 # mysql 用于操作數據庫# 后面用到什么&#xff0c;再下載創建app.js 之前&#xff0c;我們開啟一個服務器&#xff0c;js文件…

繼承上機作業

1、實現如下類之間的繼承關系&#xff0c;并編寫Music類來測試這些類 2、編寫一個Java應用程序&#xff0c;該程序包括3個類&#xff1a;Monkey類、People類和主類E。要求&#xff1a; (1) Monkey類中有個構造方法&#xff1a;Monkey (String s)&#xff0c;并且有個public voi…

ApplePay集成教程

Apple Pay運行環境&#xff1a;iPhone6以上設備&#xff0c;操作系統最低iOS9.0以上&#xff0c;部分信息設置需要iOS9.2以上。目前還不支持企業證書添加。 環境搭建好后可以在模擬器上面運行&#xff0c;xcode7.2.1iPhone6SP9.2系統下&#xff0c;系統會綁定幾種虛擬的銀行卡…

Node — 第七天 (大事件項目接口實現一)

關于JS錯誤處理 node中和mysql中的錯誤處理 node和MySQL提供的方法&#xff0c;已經對錯誤信息進行了封裝&#xff0c;只需要使用 err.message 即可獲取到錯誤信息。 比如&#xff1a; const fs require(fs); // 讀取一個不存在的文件 fs.readFile(abcd.txt, (err, data) …

1.Consul 簡介和環境搭建

1.什么是 Consul Consul 是 service mesh(服務網格)的一個解決方案&#xff0c;它提供了諸如服務發現&#xff0c;配置和隔離等功能的一整套控制平面(control plane)。開發人員可以根據需要單獨使用這些功能點&#xff0c;也可以將他們整合成為一個完整的service mesh。Consul …

Node — 第八天 (大事件項目接口實現二)

如何處理MySQL的錯誤 MySQL的錯誤信息&#xff0c;可以通過err來獲取。這是沒有問題的。 但是&#xff0c;我們加入了Promise&#xff0c;Promise中的錯誤&#xff0c;在外部是獲取不到的&#xff0c;只能使用Promise相關方法來獲取錯誤信息。 解決方法一 使用 JS原生的 tr…

在local模式下的spark程序打包到集群上運行

一、前期準備 前期的環境準備&#xff0c;在Linux系統下要有Hadoop系統&#xff0c;spark偽分布式或者分布式&#xff0c;具體的教程可以查閱我的這兩篇博客&#xff1a; Hadoop2.0偽分布式平臺環境搭建 Spark2.4.0偽分布式環境搭建 然后在spark偽分布式的環境下必須出現如下八…

Effective Objective-C 2.0 初讀小結

1.對于OC中的對象聲明例如NSObject *obj1 [NSObject new];, obj1這個指針變量是分配在棧上的, 他指向的是這一個分配在堆上面的實例對象, 如果進行下面的賦值操作NSObject *obj2 obj1;,那么并沒有新生成一個實例對象, 只是在棧上分配了一個新的指針變量obj2, 而obj2和obj1指向…

APS系統對制造企業到底有多重要?看完這5點你就明白了

第一個問題&#xff1a;需要APS嗎&#xff1f; APS是否重要&#xff0c;不能從其所體現的軟件工具或系統角度來說&#xff0c;而應該從業務角度來說。對于制造工廠和車間的運行而言&#xff0c;計劃是核心的業務。就如同那句俗話說的&#xff0c;沒有規矩不成方圓&#xff0c;領…

Node — 第九天 (大事件項目接口實現三)

文章管理接口 設計數據表 添加文章接口 編寫接口&#xff0c;使用postman模擬提交formdata類型的數據 在article.js 中&#xff0c;加入 /add 路由 postman模擬提交formdata類型的數據 multer處理文件上傳 下載安裝multer 加載模塊 const multer require(multer) 配置上…

Python之爬蟲-段子網

Python之爬蟲-段子網 https://ishuo.cn #!/usr/bin/env python # -*- coding:utf-8 -*- import re import requestsresponse requests.get(https://ishuo.cn) data response.text print(data) r re.findall(<div class"content">(.*?)</div>,data) f…

Node — 第九天 (ES6降級 and 發布屬于自己的[第三方模塊]包)

ES6降級處理 因為 ES 6 有瀏覽器兼容性問題&#xff0c;可以使用一些工具進行降級處理&#xff0c;例如&#xff1a;babel 降級處理 babel 的使用步驟 安裝 Node.js命令行中安裝 babel配置文件 .babelrc運行命令&#xff0c;完成降級 項目初始化 (項目文件夾不能有中文) npm …

Vue — 第一天(極速入門)

基本介紹 vue是什么 目標&#xff1a;了解vue的一些基礎概念。 官方網站&#xff1a; https://cn.vuejs.org/ vue是&#xff1a;漸進式javascript框架。 兩組概念 &#xff08;1&#xff09;框架 庫。只提供一些API給開發者使用。jquery 是一個js庫框架。擁有自己的規則和…

python類和實例化

簡答介紹類和實例python是面向對象的語言&#xff0c;最主要的就是類和實例&#xff0c;類是抽象的模版創建一個類class Studen(object),class 后接類名&#xff0c;定義的類名大些字母開頭&#xff0c;object為類的繼承&#xff0c;沒有合適的繼承類用object類&#xff0c;這是…

pjsip庫分析

http://blog.chinaunix.net/space.php?uid287570&doblog&cuid728411 如果你對SIP/VoIP技術感興趣,哪希望你不要錯過:),如果你對寫出堪稱優美的Code感興趣,那么你也不可錯過:)這期間我想分析一下一個實際的協議棧的設計到實現的相關技術,算是自己的一個學習經歷記錄.最…

Vue — 第二天(v-model和過濾器)

VUE-02-v-model和過濾器 昨日反饋與回顧 代碼倉庫的問題 不要修改你克隆下來的倉庫中任意代碼&#xff0c;否則&#xff0c;下次pull時&#xff0c;可能會報錯&#xff0c;從而得到不到最新的代碼。 如果已經遇到了這個沖突&#xff1a; 解決沖突(git 中解決沖突)把關鍵代碼…