koa2 框架中的中间件同步还是异步的问题?

2018-03-27 12:14:52 +08:00
 waibunleung

问题 1:为什么 koa2 框架中的中间件要用 async 的形式写,很少见用同步模式(即不加 async)? 如:

app.use(async (ctx, next) => {
  const start = new Date()
  await next()
  const ms = new Date() - start
  console.log(`${ctx.method} ${ctx.url} - ${ms}ms`)
})

查阅了一些资料,看到阮一峰的 koa 教程中,有同步写法的例子:

const one = (ctx, next) => {
  console.log('>> one');
  next();
  console.log('<< one');
}

const two = (ctx, next) => {
  console.log('>> two');
  next(); 
  console.log('<< two');
}

const three = (ctx, next) => {
  console.log('>> three');
  next();
  console.log('<< three');
}

app.use(one);
app.use(two);
app.use(three);

这里完全没有 async 的出现,阮神只是在后面提到: “迄今为止,所有例子的中间件都是同步的,不包含异步操作。如果有异步操作(比如读取数据库),中间件就必须写成 async 函数。”

接着找资料发现 koa2 中间件的 next 返回的是 promise,因为源码中的 dispatch(i)返回的就是 promise, 这样我又有一个疑问, 问题 2:为什么要设计成返回 promise ?不返回 promise 就达不到中间件串联的效果吗? 因为中间件的执行在理解上是一个同步的过程,所以设计成异步要怎么去理解??

问题 3:是不是用 koa2 写的代码都存在很多 async 的 function(公司项目代码到处都是 async 的,返回输出 json 的时候也需要 async 吗?)? 有没有不需要写 async 的场景或者例子?

6403 次点击
所在节点    Node.js
32 条回复
waibunleung
2018-03-27 20:45:56 +08:00
@VDimos 不知道你有没有见过那个 blog,那个 blog 一直在更新,我看到的文章是 20117 年下半年的,这个时候怎么都是 koa2 了吧?而且我读你的话的前半段,意思就是因为要等待 next 返回的 promise,所以用 await,因为用 await,所以要 async,我觉得这不是一个说得过去的解释....
hzzhzzdogee
2018-03-27 22:58:25 +08:00
可以用同步, 就变得像 express
hzzhzzdogee
2018-03-27 22:59:19 +08:00
有那么好用的 async await, 干嘛不用. async 正是 koa 期望的呀
waibunleung
2018-03-27 23:13:27 +08:00
@hzzhzzdogee 此话怎讲呢?
VDimos
2018-03-27 23:16:03 +08:00
@waibunleung koa 用的洋葱模型,要求一层层进去再一层层出来。nodejs 是异步的,koa 遵循了这个原则。而以前的异步最大的问题在于,如果要实现洋葱模型,就必须写大量的回调函数。因此就算是 koa1 也是采用了 generator 这种折中的方法。如果你使用过 co,你就会对洋葱模型有感觉了。其实 koa1 内部就是调用了 co。koa2 改用了新的 async 编写,async 实现的功能本身就是 generator 加 co。你如果用非 async 函数,koa 内部会把它转换成一个 async 函数的。
kohos
2018-03-27 23:51:09 +08:00
1. 函数前面加 async 的原因是因为函数里面用了 await,没用的话不加也行;
2. 返回 Promise 的函数前面加个 await 就能得到异步返回的结果,使用起来和同步一样(实际是异步);
3. koa2 的特性就是用 async/await/Promise 代替以前的回调,使代码更简洁易懂;
以前那套回调,用 Promise 包装一下就可以拿来给 koa2 使用;
不用 async/await/Promise 还继续用回调函数的话,不如继续用 expressjs
POPOEVER
2018-03-28 01:37:38 +08:00
用不用 async/await 跟用 express 或是 koa 有关系吗?我在 express 里面也会用 async 啊
leemove
2018-03-28 09:14:00 +08:00
https://leemove.github.io/2018/03/19/koa-compose/#more 这个就是 Koa 中间件的原理....看了这个应该就不会疑惑了..
waibunleung
2018-03-28 10:43:46 +08:00
@POPOEVER 我的意思是,koa2 的中间件几乎都是异步的写法,就不存在同步的写法或者场景吗?为什么要全部安排成异步的?
waibunleung
2018-03-28 10:46:35 +08:00
@leemove 我看过更详细的原理分析,就是看了才不明不为什么会安排成异步的,就是为什么 dispatch(i)要返回 promise 而不是普通函数或者对象,按照 middleware[]的顺序执行递归执行下去,应该可以达到洋葱模型吧?那这里的 promise 的意义是什么?
connection
2018-03-28 14:12:51 +08:00
问题 2:promise 一个程度上可以使得异步更精准,也就是在失败成功都可以获得它的状态改变。promise 也有助于回调的扁平。使用 promise 的话,promise 链条状,可以使得外层中间件可以获得内层中间件的状态。在错误捕获上也是有优势.
以前版本的 co+generator+thunkify 约等于 async/await
问题 3:事实上如果你的下一个中间件或者当前代码是不需要异步操作的,比如直接是返回的一些硬编码,是不用 async await 的
leemove
2018-03-28 14:22:18 +08:00
@waibunleung 设计成同步的那一旦一个 next 执行失败,就会影响整个同步执行的过程,错误处理不够优雅.而借助 promise 的特性,可以便于管理错误.

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/441745

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX