返回顶部
首页 > 资讯 > 前端开发 > node.js >详解如何让Express支持async/await
  • 427
分享到

详解如何让Express支持async/await

详解Expressawait 2022-06-04 17:06:25 427人浏览 薄情痞子
摘要

随着 node.js v8 的发布,node.js 已原生支持 async/await 函数,WEB 框架 Koa 也随之发布了 Koa 2 正式版,支持 async/await 中间件,为处理异步回调带来

随着 node.js v8 的发布,node.js 已原生支持 async/await 函数,WEB 框架 Koa 也随之发布了 Koa 2 正式版,支持 async/await 中间件,为处理异步回调带来了极大的方便。

既然 Koa 2 已经支持 async/await 中间件了,为什么不直接用 Koa,而还要去改造 Express 让其支持 async/await 中间件呢?因为 Koa 2 正式版发布才不久,而很多老项目用的都还是 Express,不可能将其推倒用 Koa 重写,这样成本太高,但又想用到新语法带来的便利,那就只能对 Express 进行改造了,而且这种改造必须是对业务无侵入的,不然会带来很多的麻烦。

直接使用 async/await

让我们先来看下在 Express 中直接使用 async/await 函数的情况。


const express = require('express');
const app = express();
const { promisify } = require('util');
const { readFile } = require('fs');
const readFileAsync = promisify(readFile);
  
app.get('/', async function (req, res, next){
 const data = await readFileAsync('./package.JSON');
 res.send(data.toString());
});
// Error Handler
app.use(function (err, req, res, next){
 console.error('Error:', err);
 res.status(500).send('Service Error');
});
  
app.listen(3000, '127.0.0.1', function (){
 console.log(`Server running at Http://${this.address().address }:${this.address().port }/`);
});

上面是没有对 Express 进行改造,直接使用 async/await 函数来处理请求,当请求 http://127.0.0.1:3000/ 时,发现请求能正常请求,响应也能正常响应。这样似乎不对 Express 做任何改造也能直接使用 async/await 函数,但如果 async/await 函数里发生了错误能不能被我们的错误处理中间件处理呢?现在我们去读取一个不存在文件,例如将之前读取的 package.json 换成 age.json 。


app.get('/', async function (req, res, next){
 const data = await readFileAsync('./age.json');
 res.send(data.toString());
});

现在我们去请求 http://127.0.0.1:3000/ 时,发现请求迟迟不能响应,最终会超时。而在终端报了如下的错误:

查看图片

发现错误并没有被错误处理中间件处理,而是抛出了一个 unhandledRejection 异常,现在如果我们用 try/catch 来手动捕获错误会是什么情况呢?


app.get('/', async function (req, res, next){
 try {
  const data = await readFileAsync('./age.json');
  res.send(datas.toString());
 } catch(e) {
  next(e);
 }
});

发现请求被错误处理中间件处理了,说明我们手动显式的来捕获错误是可以的,但是如果在每个中间件或请求处理函数里面加一个 try/catch 也太不优雅了,对业务代码有一定的侵入性,代码也显得难看。所以通过直接使用 async/await 函数的实验,我们发现对 Express 改造的方向就是能够接收 async/await 函数里面抛出的错误,又对业务代码没有侵入性。

改造 Express

在 Express 中有两种方式来处理路由和中间件,一种是通过 Express 创建的 app,直接在 app 上添加中间件和处理路由,像下面这样:


const express = require('express');
const app = express();
  
app.use(function (req, res, next){
 next();
});
app.get('/', function (req, res, next){
 res.send('hello, world');
});
app.post('/', function (req, res, next){
 res.send('hello, world');
});
  
app.listen(3000, '127.0.0.1', function (){
 console.log(`Server running at http://${this.address().address }:${this.address().port }/`);
});

另外一种是通过 Express 的 Router 创建的路由实例,直接在路由实例上添加中间件和处理路由,像下面这样:


const express = require('express');
const app = express();
const router = new express.Router();
app.use(router);
  
router.get('/', function (req, res, next){
 res.send('hello, world');
});
router.post('/', function (req, res, next){
 res.send('hello, world');
});
  
app.listen(3000, '127.0.0.1', function (){
 console.log(`Server running at http://${this.address().address }:${this.address().port }/`);
});

这两种方法可以混合起来用,现在我们思考一下怎样才能让一个形如 app.get('/', async function(req, res, next){}) 的函数,让里面的 async 函数抛出的错误能被统一处理呢?要让错误被统一的处理当然要调用 next(err) 来让错误被传递到错误处理中间件,又由于 async 函数返回的是 Promise,所以肯定是形如这样的 asyncFn().then().catch(function(err){ next(err) }) ,所以按这样改造一下就有如下的代码:


app.get = function (...data){
 const params = [];
 for (let item of data) {
  if (Object.prototype.toString.call(item) !== '[object AsyncFunction]') {
   params.push(item);
   continue;
  }
  const handle = function (...data){
   const [ req, res, next ] = data;
   item(req, res, next).then(next).catch(next);
  };
  params.push(handle);
 }
 app.get(...params)
}

上面的这段代码中,我们判断 app.get() 这个函数的参数中,若有 async 函数,就采用 item(req, res, next).then(next).catch(next); 来处理,这样就能捕获函数内抛出的错误,并传到错误处理中间件里面去。但是这段代码有一个明显的错误就是最后调用 app.get(),这样就递归了,破坏了 app.get 的功能,也根本处理不了请求,因此还需要继续改造。

我们之前说 Express 两种处理路由和中间件的方式可以混用,那么我们就混用这两种方式来避免递归,代码如下:


const express = require('express');
const app = express();
const router = new express.Router();
app.use(router);
  
app.get = function (...data){
 const params = [];
 for (let item of data) {
  if (Object.prototype.toString.call(item) !== '[object AsyncFunction]') {
   params.push(item);
   continue;
  }
  const handle = function (...data){
   const [ req, res, next ] = data;
   item(req, res, next).then(next).catch(next);
  };
  params.push(handle);
 }
 router.get(...params)
}

像上面这样改造之后似乎一切都能正常工作了,能正常处理请求了。但通过查看 Express 的源码,发现这样破坏了 app.get() 这个方法,因为 app.get() 不仅能用来处理路由,而且还能用来获取应用的配置,在 Express 中对应的源码如下:


methods.forEach(function(method){
 app[method] = function(path){
  if (method === 'get' && arguments.length === 1) {
   // app.get(setting)
   return this.set(path);
  }
  
  this.lazyrouter();
  
  var route = this._router.route(path);
  route[method].apply(route, slice.call(arguments, 1));
  return this;
 };
});

所以在改造时,我们也需要对 app.get 做特殊处理。在实际的应用中我们不仅有 get 请求,还有 post、put 和 delete 等请求,所以我们最终改造的代码如下:


const { promisify } = require('util');
const { readFile } = require('fs');
const readFileAsync = promisify(readFile);
const express = require('express');
const app = express();
const router = new express.Router();
const methods = [ 'get', 'post', 'put', 'delete' ];
app.use(router);
  
for (let method of methods) {
 app[method] = function (...data){
  if (method === 'get' && data.length === 1) return app.set(data[0]);

  const params = [];
  for (let item of data) {
   if (Object.prototype.toString.call(item) !== '[object AsyncFunction]') {
    params.push(item);
    continue;
   }
   const handle = function (...data){
    const [ req, res, next ] = data;
    item(req, res, next).then(next).catch(next);
   };
   params.push(handle);
  }
  router[method](...params);
 };
}
   
app.get('/', async function (req, res, next){
 const data = await readFileAsync('./package.json');
 res.send(data.toString());
});
   
app.post('/', async function (req, res, next){
 const data = await readFileAsync('./age.json');
 res.send(data.toString());
});
  
router.use(function (err, req, res, next){
 console.error('Error:', err);
 res.status(500).send('Service Error');
}); 
   
app.listen(3000, '127.0.0.1', function (){
 console.log(`Server running at http://${this.address().address }:${this.address().port }/`);
});

现在就改造完了,我们只需要加一小段代码,就可以直接用 async function 作为 handler 处理请求,对业务也毫无侵入性,抛出的错误也能传递到错误处理中间件。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: 详解如何让Express支持async/await

本文链接: https://lsjlt.com/news/12334.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 详解如何让Express支持async/await
    随着 Node.js v8 的发布,Node.js 已原生支持 async/await 函数,Web 框架 Koa 也随之发布了 Koa 2 正式版,支持 async/await 中间件,为处理异步回调带来...
    99+
    2022-06-04
    详解 Express await
  • 如何理解Await与Async
    这篇文章主要介绍“如何理解Await与Async ”,在日常操作中,相信很多人在如何理解Await与Async 问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解Awai...
    99+
    2024-04-02
  • 如何理解JavaScript的async/await
    这篇文章将为大家详细讲解有关如何理解JavaScript的async/await,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。随着 Node 7 的发布,越...
    99+
    2024-04-02
  • async/await如何让异步操作同步执行
    小编给大家分享一下async/await如何让异步操作同步执行,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一.前言我们经常会遇到这样的麻烦事,多个函数按顺序执行,返回结果却不是我们预期的...
    99+
    2024-04-02
  • JS中如何优雅的使用async await详解
    目录jQuery的$.ajax Webpack时代的开始 深入了解Promise 消灭嵌套 await-to-js 总结jQuery的$.ajax 在开始之前我们先来聊聊我的js异...
    99+
    2024-04-02
  • 如何让你的Nginx支持分布式追踪详解
    目录Background源码构建nginx-opentracing准备nginx-opentracing准备jaeger-client-cpp编译gcc编译cmake编译jaeger...
    99+
    2024-04-02
  • 如何用async/await解决交通灯问题
    这篇文章主要介绍“如何用async/await解决交通灯问题”,在日常操作中,相信很多人在如何用async/await解决交通灯问题问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解...
    99+
    2024-04-02
  • 如何让deno支持HTTP服务
    这篇文章主要介绍“如何让deno支持HTTP服务”,在日常操作中,相信很多人在如何让deno支持HTTP服务问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何让deno支持H...
    99+
    2024-04-02
  • 如何让nodeJS支持ES6的babel
    小编给大家分享一下如何让nodeJS支持ES6的babel,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!要使用Babel, 我们...
    99+
    2024-04-02
  • ES6如何使用Async/Await结合数组解构
    这篇文章将为大家详细讲解有关ES6如何使用Async/Await结合数组解构,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Async/Await结合数组解构数组解构非常赞...
    99+
    2024-04-02
  • 如何理解C# 5.0的新特性Async和Await
    今天就跟大家聊聊有关如何理解C# 5.0的新特性Async和Await,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。一、引言在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4...
    99+
    2023-06-17
  • 详解node如何让一个端口同时支持https与http
    众所周知node是一个高性能的web服务器,使用它可以很简单的创建一个http或https的服务器。 比如一个很简单的http服务器: var http = require('http'); var ...
    99+
    2022-06-04
    端口 详解 http
  • 如何让MYSQL彻底支持中文
    本篇内容主要讲解“如何让MYSQL彻底支持中文”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“如何让MYSQL彻底支持中文”吧!  先将让slack支持中文,方法...
    99+
    2024-04-02
  • Vue2如何支持compositionAPI示例详解
    目录前言如何使用原理解析响应式( ref reactive 的实现)总结前言 自从 Vue3 发布之后,composition API 这个词走入写 Vue 同学的视野之中,相信大...
    99+
    2023-01-13
    Vue 支持composition API Vue composition API
  • 如何解析异步编程In .NET APM/EAP和async/await
    如何解析异步编程In .NET APM/EAP和async/await,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。概述在之前写的一篇关于async和await的前世今生的文章...
    99+
    2023-06-17
  • 如何让小程序支持JSX语法
    今天小编给大家分享一下如何让小程序支持JSX语法的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下...
    99+
    2024-04-02
  • 如何让IE下支持Html5的placeholder属
    这篇文章将为大家详细讲解有关如何让IE下支持Html5的placeholder属,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。 HTML5对Web Form做了许多增强...
    99+
    2024-04-02
  • Ubuntu如何立即让网络支持nat
    小编给大家分享一下Ubuntu如何立即让网络支持nat,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!立即让网络支持natsudo echo 1...
    99+
    2023-06-27
  • 如何让bootstrap的carousel支持滑动滚屏
    小编给大家分享一下如何让bootstrap的carousel支持滑动滚屏,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!原始的轮播...
    99+
    2024-04-02
  • 如何快速让你的代码支持Cocoapods!
    Show me the code !此次分享的是如何让你的代码框架上传到cocoapods,方便使用!对了,在第一句之前应该介绍cocoapods的背景,但作为iOS developer,不用介绍都知道其重要性,OK,Talk is che...
    99+
    2023-06-04
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作