首頁 > web前端 > js教程 > 主體

Express發展歷程

巴扎黑
發布: 2017-09-11 10:09:28
原創
2012 人瀏覽過

這篇文章主要介紹了淺談Express非同步進化史 ,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧

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位址

#

以上是Express發展歷程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!