php中文网 | cnphp.com

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 619|回复: 0

使用异步编程保证Koa的洋葱模型

[复制链接]

2670

主题

2677

帖子

9495

积分

管理员

Rank: 9Rank: 9Rank: 9

UID
1
威望
0
积分
6703
贡献
0
注册时间
2021-4-14
最后登录
2024-5-15
在线时间
674 小时
QQ
发表于 2022-1-14 08:14:36 | 显示全部楼层 |阅读模式
koa框架的业务流程是一个完全的异步编程模型,通过ctx上下文对象来贯穿http的上下游。对我们来说最重要的就是理解洋葱模型。

先来看一个经典的洋葱图认识一下
image.png
我们先来看一下这个代码

[mw_shl_code=applescript,true]const Koa = require('koa')
const app = new Koa()
//第一个中间件
app.use((ctx, next) => {
    console.log("第一个中间件", 1);
    next()
    console.log("第一个中间件", 2);
})
//第二个中间件
app.use((ctx, next) => {
    console.log("第二个中间件", 3);
    next()
    console.log("第二个中间件", 4);
})
//第三个中间件
app.use((ctx, next) => {
    console.log("第三个中间件", 5);
    console.log("第三个中间件", 6);
})
app.listen(3000, () => {
    console.log("Koa已经开启在http://loclhost:3000");
})
[/mw_shl_code]
我们运行这个代码在浏览器打开并返回控制台看一下打印

第一个中间件 1
第二个中间件 3
第三个中间件 5
第三个中间件 6
第二个中间件 4
第一个中间件 2

大家可以看这段代码,其执行效果为135642,也就是说这就好比第一个中间件把第二个包裹了起来,第三个中间件又把第二个中间件包起来了,调用next时就回去执行第二个中间件,结束后继续执行第一个。
image.png
所以他的顺序应该是这样的

image.png
看到上图相信大家已经非常的了解了吧。

然后下面我们会用到async await这个语法糖,我在这里简单介绍一下async函数

它是generator函数的语法糖,可以通过 yield(中文翻译动词为提供,暂时叫他提供) 关键字,就是把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案。

async函数,就是将generator函数的*换成async,将yield替换成await

简单来说async/await,就是异步编程回调函数写法的替代方法,暂且就说这么多,下一篇文章我再详细介绍async await函数,

再多说一句 async 函数执行时,如果遇到 await 就会先暂停执行 ,等到触发的异步操作完成后,恢复 async 函数的执行并返回解析值。

我们再反观这个洋葱模型

然后我再在第三个中间件加了个axios请求,因为他是异步的操作,所以我得再在前面加个async,然后再在请求的前面加个await,这样我们就可以得到get请求的这个结果,如果不加,他返回的是一个Promise对象

image.png
这里是加了async await函数的,但是…

[mw_shl_code=applescript,true]const Koa = require('koa')
const app = new Koa()
    //第一个中间件
app.use((ctx, next) => {
        console.log("第一个中间件", 1);
        next()
        console.log("第一个中间件", 2);
    })
    //第二个中间件
app.use((ctx, next) => {
        console.log("第二个中间件", 3);
        next()
        console.log("第二个中间件", 4);
    })
    //第三个中间件
app.use(async(ctx, next) => {
    console.log("第三个中间件", 5);
    const axios = require("axios")
    const res = await axios.get('http://www.baidu.com')
    console.log(res);
    console.log('发送了axios请求');
    console.log("第三个中间件", 6);
})
app.listen(3000, () => {
    console.log("Koa已经开启在http://localhost:3000");
})
[/mw_shl_code]
我们自行打印这个结果,可以看到

image.png

中间省略…

image.png
可以看到,我们虽然取回了这个res结果,但是它的打印顺序变了,也就是它遇到await后就会先暂停执行 ,等到触发的异步操作完成后,恢复 async 函数的执行并返回解析值。

但是这不符合我们想要的结果,我们想要的是它按照本来的顺序执行,

然后我们为了保证洋葱模型,我们应该如下改动,将前面的代码也添加async await用来控制情况在我们预期之内。
[mw_shl_code=applescript,true]const Koa = require('koa')
const app = new Koa()
//第一个中间件
app.use(async(ctx, next) => {
    console.log("第一个中间件", 1);
    await next()
    console.log("第一个中间件", 2);
})
//第二个中间件
app.use(async(ctx, next) => {
    console.log("第二个中间件", 3);
    await next()
    console.log("第二个中间件", 4);
})
//第三个中间件
app.use(async(ctx, next) => {
    console.log("第三个中间件", 5);
    const axios = require("axios")
    const res = await axios.get('http://www.baidu.com')
    console.log('发送了axios请求');
    console.log("第三个中间件", 6);
})
app.listen(3000, () => {
    console.log("Koa已经开启在http://loclhost:3000");
})
[/mw_shl_code]
运行代码我们可以看到

image.png
中间省略…
image.png
所以我们在写中间件函数的时候,一般都将中间件变成async await函数,这样就不会因为异步编程导致洋葱模型不可控以至于不合理





上一篇:初识 Rust,作为新势力它的前景如何
下一篇:什么是前端开发?什么是后端开发?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|php中文网 | cnphp.com ( 赣ICP备2021002321号-2 )

GMT+8, 2024-5-17 11:30 , Processed in 0.151756 second(s), 35 queries , Gzip On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

申明:本站所有资源皆搜集自网络,相关版权归版权持有人所有,如有侵权,请电邮(fiorkn@foxmail.com)告之,本站会尽快删除。

快速回复 返回顶部 返回列表