国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

淺談Express異步進化史

2019-11-19 15:30:10
字體:
來源:轉載
供稿:網友

1、導言

在 Javascript 的世界里,異步(由于JavaScript的單線程運行,所以JavaScript中的異步是可以阻塞的)無處不在。

Express 是 node 環境中非常流行的Web服務端框架,有很大比例的 Node Web應用 采用了 Express。

當使用 JavaScript 編寫服務端代碼時,我們無可避免的會大量使用到異步。隨著 JavaScript、Node 的進化,我們的異步處理方式,也就隨之進化。

接下來,我們就來看看 Express 中異步處理的進化過程。

2、JavaScript的異步處理

在異步的世界里,我們需要想辦法獲取的異步方法完畢的通知,那在 JavaScript 中,會有哪些方式呢?

2.1、回調

回調是 JS 中最原始,也是最古老的異步通知機制。

function asyncFn(callback) { // 利用setTimeout模擬異步 setTimeout(function () {  console.log('執行完畢');  callback(); // 發通知 }, 2000);}asyncFn(function () { console.log('我會在2s后輸出');});

2.2、事件監聽

要獲取結果的函數,監聽某個時間。在異步方法完成后,觸發該事件,達到通知的效果。

2.3、發布/訂閱

通過觀察者模式,在異步完成時,修改發布者。這個時候,發布者會把變更通知到訂閱者。

2.4、Promise

Promise 是回調函數的改進。使用它, 我們可以將異步平行化,避免回調地獄。

function asyncFn() { return new Promise((resolve, reject) => {  // 利用setTimeout模擬異步  setTimeout(function () {   console.log('執行完畢');   resolve(); // 發通知(是否有感覺到回調的影子?)  }, 2000); });}asyncFn() .then(function () {  console.log('我會在2s后輸出'); });

2.5、生成器(Generator)

Generator 函數是 ES6 提供的一種異步編程解決方案。

以下代碼只是簡單演示,實際上 Generator 的使用過程,相對是比較復雜的,這是另外一個話題,本文暫且不表。

function asyncFn() { return new Promise((resolve, reject) => {  // 利用setTimeout模擬異步  setTimeout(function () {   console.log('執行完畢');   resolve(); // 發通知(是否有感覺到回調的影子?)  }, 2000); });}function* generatorSync() { var result = yield asyncFn();}var g = generatorSync();g.next().value.then(()=>{ console.log('我會在2s后輸出');});

2.6、async...await

可以說是當前 JavaScript 中,處理異步的最佳方案。

function asyncFn() { return new Promise((resolve, reject) => {  // 利用setTimeout模擬異步  setTimeout(function () {   console.log('執行完畢');   resolve(); // 發通知(是否有感覺到回調的影子?)  }, 2000); });}async function run(){ await asyncFn(); console.log('我會在2s后輸出');}run();

3、Express中的異步處理

在Express中,我們一般常用的是方案是:回調函數、Promise、以及async...await。

為了搭建演示環境,通過 express-generator 初始化一個express項目。一般的服務端項目,都是路由調用業務邏輯。所以,我們也遵循這個原則:

打開 routs/index.js,我們會看到如下內容,以下Demo就以此文件來做演示。

var express = require('express');var router = express.Router();/* GET home page. */router.get('/', function(req, res, next) { res.render('index', { title: 'Express' });});module.exports = router;

3.1、回調函數處理Express異步邏輯

在 Express 中,路由可以加載多個中間件,所以我們可以把業務邏輯按照中間件的寫法進行編寫。這樣通過一層層的next,就能非常方便的拆分異步邏輯。

var express = require('express');var router = express.Router();function asyncFn(req, res, next) { setTimeout(() => {  req.user = {}; // 設置當前請求的用戶  next(); }, 2000);}function asyncFn2(req, res, next) { setTimeout(() => {  req.auth = {}; // 設置用戶權限  next(); }, 2000);}function asyncFn3(req, res, next) { setTimeout(() => {  res.locals = { title: 'Express Async Test' }; // 設置數據  res.render('index'); // 響應 }, 2000);}/* GET home page. */router.get('/', asyncFn, asyncFn2, asyncFn3); // 一步步執行中間件module.exports = router;

3.2、Promise 處理Express異步邏輯

該方案中,將多個業務邏輯,包裝為返回 Promise 的函數。通過業務方法進行組合調用,以達到一進一出的效果。

var express = require('express');var router = express.Router();function asyncFn(req, res) { return new Promise((resolve, reject) => {  setTimeout(() => {   req.user = {}; // 設置當前請求的用戶   resolve(req);  }, 2000); });}function asyncFn2(req) { return new Promise((resolve, reject) => {  setTimeout(() => {   req.auth = {}; // 設置用戶權限   resolve();  }, 2000); });}function asyncFn3(res) { return new Promise((resolve, reject) => {  setTimeout(() => {   res.locals = { title: 'Express Async Test' }; // 設置數據   res.render('index'); // 響應  }, 2000); });}function doBizAsync(req, res, next) { asyncFn(req)  .then(() => asyncFn2(req))  .then(() => asyncFn3(res))  .catch(next); // 統一異常處理};/* GET home page. */router.get('/', doBizAsync);module.exports = router;

3.3、async...await 處理Express異步邏輯

實際上,該方案也是需要 Promise 的支持,只是寫法上,更直觀,錯誤處理也更直接。

需要注意的是,Express是早期的方案,沒有對async...await進行全局錯誤處理,所以可以采用包裝方式,進行處理。

var express = require('express');var router = express.Router();function asyncFn(req) { return new Promise((resolve, reject) => {  setTimeout(() => {   req.user = {}; // 設置當前請求的用戶   resolve(req);  }, 2000); });}function asyncFn2(req) { return new Promise((resolve, reject) => {  setTimeout(() => {   req.auth = {}; // 設置用戶權限   resolve();  }, 2000); });}function asyncFn3(res) { return new Promise((resolve, reject) => {  setTimeout(() => {  }, 2000); });}async function doBizAsync(req, res, next) { var result = await asyncFn(req); var result2 = await asyncFn2(req); res.locals = { title: 'Express Async Test' }; // 設置數據 res.render('index'); // 響應};const tools = { asyncWrap(fn) {  return (req, res, next) => {   fn(req, res, next).catch(next); // async...await在Express中的錯誤處理  } }};/* GET home page. */router.get('/', tools.asyncWrap(doBizAsync)); // 需要用工具方法包裹一下module.exports = router;

4、總結

雖然 koa 對更新、更好的用法(koa是generator,koa2原生async)支持的更好。但作為從 node 0.x 開始跟的我,對 Express 還是有特殊的好感。

以上的一些方案,已經與 koa 中使用無異,配合 Express 龐大的生態圈,無異于如虎添翼。

本文Github地址

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 措美县| 南安市| 民县| 临沭县| 阿拉善右旗| 洛浦县| 新巴尔虎右旗| 营山县| 望谟县| 金平| 临江市| 灯塔市| 漳州市| 涿州市| 海城市| 保山市| 普定县| 宁夏| 潜江市| 交口县| 南召县| 什邡市| 安义县| 阆中市| 鹤山市| 子长县| 老河口市| 延庆县| 湘潭县| 习水县| 碌曲县| 锦州市| 宁化县| 安福县| 秭归县| 石城县| 南投县| 商城县| 大姚县| 修水县| 宁明县|