image.png

eggjs洋葱圈模型

config/config.default.js里面不需要引入 middleware,直接写中间件的名字

  1. config.middleware = ['m1', 'm2', 'm3']
  2. // 中间件的 options参数
  3. config.m1 = { title: 'middlware1', type: 'chart' }

middleware里面如果没有 next,页面会显示 404
必须的一步, await next()

middleware

app/middleware/m1.js

  1. module.exports = options => {
  2. return async (ctx, next) => {
  3. console.log(ctx);
  4. await next();
  5. }
  6. }
  • options 中间件的配置参数
  • ctx 当前的上下文
  • next 下一个中间件

koa洋葱圈模型

  1. const Koa = require('koa');
  2. const app = new Koa(); // 应用程序对象
  3. function getUesr(ctx, next) {}
  4. app.use(getUser);
  5. app.use((ctx, next) => {
  6. console.log(10);
  7. next();
  8. console.log(20);
  9. })
  10. app.use((ctx, next) => {
  11. console.log(30);
  12. next();
  13. console.log(40);
  14. })
  • console顺序 10 -> 30 -> 40 -> 20
  • 先执行第一个中间件,打印 10, 然后执行第二个中间件,打印 30

async & awit

异步编程,async & await 洋葱模型
如果不加上 async await,不能保证所有中间件都是按照洋葱模型来执行的

  • next() 返回一定是 Promise
  • 如果 next() 返回 undefined,那就是第二个中间件没有返回值 ```javascript app.use(async (ctx, next) => { console.log(10); await next(); console.log(20); });

app.use(async (ctx, next) => { console.log(30); await next(); console.log(40); });

  1. 强制 Promise<br />异步都用 async & await<br />![image.png](https://cdn.nlark.com/yuque/0/2021/png/112859/1623323816409-3ed2dd73-bd39-4e83-a91b-e5372b8d4ddf.png#clientId=u7e6ba793-bb1a-4&crop=0.0429&crop=0.1339&crop=0.9517&crop=0.8734&from=paste&height=295&id=u5f4bc8d5&margin=%5Bobject%20Object%5D&name=image.png&originHeight=857&originWidth=1556&originalType=binary&ratio=2&rotation=0&showTitle=false&size=85124&status=done&style=none&taskId=u2cf925f7-2fec-4bd3-8f2c-9e250180306&title=&width=535.9957275390625)
  2. <a name="ooc8Q"></a>
  3. ### next返回值
  4. next的返回值,会被强制的包装成 Promise
  5. - 如果不用 async,可以通过 result.then来获取 Promise的返回值,这样的写法很啰嗦
  6. - 如何直接获取 Promise的值,就用 await
  7. - 如果用 await就必须用 async,所以,推荐中间件都用 async & await
  8. 推荐 next都返回 Promise
  9. ```jsx
  10. app.use((ctx, next) => {
  11. console.log(10);
  12. const result = next();
  13. console.log(result);
  14. result.then(res => { console.log(res) });
  15. console.log(200);
  16. });
  17. app.use((ctx, next) => {
  18. console.log(30);
  19. console.log(40);
  20. return 100 // Promise {100}
  21. });
  • 执行顺序: 10 -> 30 -> 40 -> Promise {100} -> 200

async

async 会把一个函数包装成一个 Promise;
函数的任意返回值都会被包装成一个 Promise

  1. async function func() {
  2. return 100
  3. }
  4. console.log(func()); // Promise {100}

为什么中间件函数要加上 async?

  • 因为中间件函数调用了 await,如果不加 async,直接使用 await会报错
  • 其实,中间件函数不加 async,返回的也是 Promise
  • 中间件使用 await next() 就是为了保证中间件的洋葱模型,按照顺序执行
  • 洋葱模型以 next为分界线

await求值

await直译为等待,会阻塞线程,阻塞当前线程
await也可以求值,后面跟着个表达式,对表达式求值
await可以把一个异步的调用,变成一个同步的调用

  1. await 100 * 200;

对资源的操作,都是异步的

  • 读取文件
  • 写入文件
  • 上传文件
  • 发送 http请求
  • 操作数据库

一定要保证洋葱圈模型

如果中间件使用 await next,就会阻塞线程,直接进入到下一步;等 await执行完成后,才会执行下面的代码

  1. app.use((ctx, next) => {
  2. console.log(10);
  3. next();
  4. console.log(20);
  5. });
  6. app.use(async (ctx, next) => {
  7. console.log(30);
  8. await next();
  9. console.log(40);
  10. });

执行顺序:10 -> 30 -> 20 -> 40

保证中间件按照洋葱模型执行的条件:
next前面必须使用 await

  • 中间件函数执行是有顺序的
  • next之前的代码,说明中间件还没执行完成
  • next之后的代码,说明后面的中间件都执行完成了