Rumah hujung hadapan web tutorial js 让Express支持async方法分享

让Express支持async方法分享

Jan 26, 2018 pm 04:36 PM
async express kongsi

本文主要介绍了详解如何让Express支持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 }/`);
});
Salin selepas log masuk

上面是没有对 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());
});
Salin selepas log masuk

现在我们去请求 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);
 }
});
Salin selepas log masuk

发现请求被错误处理中间件处理了,说明我们手动显式的来捕获错误是可以的,但是如果在每个中间件或请求处理函数里面加一个 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 }/`);
});
Salin selepas log masuk

另外一种是通过 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 }/`);
});
Salin selepas log masuk

这两种方法可以混合起来用,现在我们思考一下怎样才能让一个形如 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)
}
Salin selepas log masuk

上面的这段代码中,我们判断 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)
}
Salin selepas log masuk

像上面这样改造之后似乎一切都能正常工作了,能正常处理请求了。但通过查看 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;
 };
});
Salin selepas log masuk

所以在改造时,我们也需要对 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 }/`);
});
Salin selepas log masuk

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

相关推荐:

NodeJs通过async和await处理异步的方法

Node.js中如何使用async函数

ES6之async+await同步/异步方案详解

Atas ialah kandungan terperinci 让Express支持async方法分享. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌
Akan R.E.P.O. Ada Crossplay?
1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Bagaimana untuk berkongsi Quark Netdisk ke Baidu Netdisk? Bagaimana untuk berkongsi Quark Netdisk ke Baidu Netdisk? Mar 14, 2024 pm 04:40 PM

Quark Netdisk dan Baidu Netdisk adalah kedua-dua alat storan yang sangat mudah Ramai pengguna bertanya sama ada kedua-dua perisian ini boleh dikendalikan? Bagaimana untuk berkongsi Quark Netdisk ke Baidu Netdisk? Biarkan laman web ini memperkenalkan kepada pengguna secara terperinci cara menyimpan fail Quark Network Disk ke Baidu Network Disk. Cara menyimpan fail dari Cakera Rangkaian Quark ke Cakera Rangkaian Baidu Kaedah 1. Jika anda ingin tahu cara memindahkan fail dari Cakera Rangkaian Quark ke Cakera Rangkaian Baidu, mula-mula muat turun fail yang perlu disimpan pada Cakera Rangkaian Quark, dan kemudian buka klien Cakera Rangkaian Baidu , pilih folder tempat fail yang dimampatkan akan disimpan dan klik dua kali untuk membuka folder. 2. Selepas membuka folder, klik "Muat naik" di penjuru kiri sebelah atas tetingkap. 3. Cari fail termampat yang perlu dimuat naik pada komputer anda dan klik untuk memilihnya.

Cara berkongsi Muzik Awan NetEase ke WeChat Moments_Tutorial untuk berkongsi Muzik Awan NetEase ke Momen WeChat Cara berkongsi Muzik Awan NetEase ke WeChat Moments_Tutorial untuk berkongsi Muzik Awan NetEase ke Momen WeChat Mar 25, 2024 am 11:41 AM

1. Mula-mula, kami masukkan Muzik Awan NetEase, dan kemudian klik pada antara muka laman utama perisian untuk memasuki antara muka main balik lagu. 2. Kemudian dalam antara muka main balik lagu, cari butang fungsi perkongsian di bahagian atas sebelah kanan, seperti yang ditunjukkan dalam kotak merah dalam rajah di bawah, klik untuk memilih saluran perkongsian dalam saluran perkongsian, klik pilihan "Kongsi ke". bahagian bawah, dan kemudian pilih "WeChat Moments" yang pertama membolehkan anda berkongsi kandungan ke WeChat Moments.

Adakah async untuk es6 atau es7? Adakah async untuk es6 atau es7? Jan 29, 2023 pm 05:36 PM

async ialah es7. async dan await ialah penambahan baharu kepada ES7 dan merupakan penyelesaian untuk operasi asynchronous/wait boleh dikatakan sebagai gula sintaktik untuk modul bersama dan fungsi penjana, menyelesaikan kod tak segerak dengan semantik yang lebih jelas. Seperti namanya, async bermaksud "tak segerak".

Cara menggunakan ekspres untuk mengendalikan muat naik fail dalam projek nod Cara menggunakan ekspres untuk mengendalikan muat naik fail dalam projek nod Mar 28, 2023 pm 07:28 PM

Bagaimana untuk mengendalikan muat naik fail? Artikel berikut akan memperkenalkan kepada anda cara menggunakan ekspres untuk mengendalikan muat naik fail dalam projek nod saya harap ia akan membantu anda!

Cara berkongsi fail dengan rakan di Baidu Netdisk Cara berkongsi fail dengan rakan di Baidu Netdisk Mar 25, 2024 pm 06:52 PM

Baru-baru ini, klien Android Baidu Netdisk telah memperkenalkan versi baharu 8.0.0 Versi ini bukan sahaja membawa banyak perubahan, tetapi juga menambah banyak fungsi praktikal. Antaranya, yang paling menarik perhatian ialah peningkatan fungsi perkongsian folder. Kini, pengguna boleh dengan mudah menjemput rakan untuk menyertai dan berkongsi fail penting dalam kerja dan kehidupan, mencapai kerjasama dan perkongsian yang lebih mudah. Jadi bagaimana anda berkongsi fail yang anda perlukan untuk berkongsi dengan rakan-rakan anda Di bawah, editor laman web ini akan memberikan pengenalan terperinci kepada anda. 1) Buka Baidu Cloud APP, mula-mula klik untuk memilih folder yang berkaitan pada halaman utama, dan kemudian klik ikon [...] di penjuru kanan sebelah atas antara muka (seperti yang ditunjukkan di bawah) 2) Kemudian klik [+] masuk; lajur "Ahli Dikongsi" 】, dan akhirnya semak semua

Apakah kunci pengaktifan untuk edisi perusahaan win7? Apakah kunci pengaktifan untuk edisi perusahaan win7? Jul 09, 2023 pm 03:01 PM

Adakah anda mempunyai kunci pengaktifan terkini untuk edisi perusahaan win7? Jika anda memasang versi perusahaan win7 rasmi, anda akan digesa untuk mengaktifkannya dengan kunci produk windows7 enterprise, jika tidak, ia tidak akan berfungsi dengan betul. Jadi editor akan berkongsi dengan anda beberapa kata laluan pengaktifan versi perusahaan win7, mari kita lihat. Q3VMJ-TMJ3M-99RF9-CVPJ3-Q7VF3KGMPT-GQ6XF-DM3VM-HW6PR-DX9G8MT39G-9HYXX-J3V3Q-RPXJB-RQ6D79JBBV-7Q7P7-CTDB7-KYBKG-X8HHQDDH2BKG-X8HHCPY6BKG Q

Perkongsian akaun ahli tv mangga 2023 Perkongsian akaun ahli tv mangga 2023 Feb 07, 2024 pm 02:27 PM

Mango TV mempunyai pelbagai jenis filem, siri TV, rancangan pelbagai dan sumber lain, dan pengguna bebas memilih untuk menontonnya. Ahli Mango TV bukan sahaja boleh menonton semua drama VIP, tetapi juga menetapkan kualiti gambar definisi tertinggi untuk membantu pengguna menonton drama dengan gembira Di bawah, editor akan membawakan anda beberapa akaun keahlian Mango TV percuma untuk digunakan oleh pengguna, cepat dan lihat. Cuba tengok. Perkongsian percuma akaun ahli terbaru Mango TV 2023: Nota: Ini adalah akaun ahli terkini yang dikumpul, anda boleh log masuk dan menggunakannya secara terus, jangan tukar kata laluan sesuka hati. Nombor akaun: 13842025699 Kata laluan: qds373 Nombor akaun: 15804882888 Kata laluan: evr6982 Nombor akaun: 13330925667 Kata laluan: jgqae Nombor akaun: 1703

Selesaikan masalah bahawa perkongsian Discuz WeChat tidak dapat dipaparkan Selesaikan masalah bahawa perkongsian Discuz WeChat tidak dapat dipaparkan Mar 09, 2024 pm 03:39 PM

Tajuk: Untuk menyelesaikan masalah yang dikongsi oleh Discuz WeChat tidak dapat dipaparkan, contoh kod khusus diperlukan Dengan pembangunan Internet mudah alih, WeChat telah menjadi bahagian yang sangat diperlukan dalam kehidupan seharian orang ramai. Dalam pembangunan tapak web, untuk meningkatkan pengalaman pengguna dan mengembangkan pendedahan laman web, banyak tapak web akan menyepadukan fungsi perkongsian WeChat, membolehkan pengguna berkongsi kandungan tapak web dengan mudah ke kumpulan Moments atau WeChat. Walau bagaimanapun, kadangkala apabila menggunakan sistem forum sumber terbuka seperti Discuz, anda akan menghadapi masalah yang dikongsi WeChat tidak dapat dipaparkan, yang membawa kesukaran tertentu kepada pengalaman pengguna.

See all articles