收藏
评论

在后端使用Go语言异步执行逻辑运算代码官方


你好,我是李艺。

上节课我们主要学习了,如何在小程序里面开启worker线程,这节课学习如何在后端异步执行运算代码。

首先看一下问题,用户设备的性能与服务器相比肯定是不可同日而语的。对于某些大数据量的一个运算,与其放在用户设备里边委曲求全,那不如在服务器上运算好了再传递给用户使用。这种情况特别适合运算量大,用户网速还比较快这样的一种情况。如果后端服务器又有边缘计算节点的话,这个方案就更加完美了。在用户量足够大的一个情况下,针对相同输入条件的计算结果,在服务器上还可以做缓存,那服务器同时向N多用户提供这个数据服务,还可以从整体上节省计算资源。下面我们看项目实践。


首先看实践一,创建后端计算接口。

下面我们要扩展出一个stopwatch_nw这样的一个组件。这个组件在获取毫秒消逝时间的格式化字符串的时候,它并不是在本地计算的,而是通过这个接口将这个毫秒数传递给服务器,然后由这个服务器计算好了以后再展示给这个用户。诚然我们这个场景有点小题大做,如果只是格式化时间字符串的话,确实不值得这样去做。在这个地方我们也只是用这样的一种方式演示这种优化技巧。首先我们需要创建一个后端接口,之前我们已经写过Go语言的格式化时间字符串的代码,我们可以将那些代码进行复用,用于创建新的接口。

下面我们进行实践一的代码演示。

编写后端接口,最好使用VSCode编辑器。

首先我们要看一下我们的后端代码在哪里,到目前为止我们还没有看我们的后端代码。简单对它做一个小的介绍 ,server这个就是我们后端代码所在的目录。整个这样的一个目录它其实是一个基于Go语言和Iris,然后写的项目模板这里边有models,有mysql routers等等。还有views ,还支持这个模板相对是比较全的。基于这个项目模板去写后端的管理程序也是可以的。包括这个接口 写接口也是可以的,写一些简单的接口都是没有问题的。它的主文件是在这个地方 main.go,在这个地方,这是它的一个主文件,它里面会有一些启动代码,我们在测试的时候,启动的时候是怎么样去启动的,我们看一眼打开集成终端。集成终端打开以后,我们可以看到这里面可能会有很多。前面这一个,这个是我们已经启动的,怎么启动我们可以把它停一下,停一下以后看一下 yarn dev就是启动了。dev是我们的。有问题了,这是因为我们前面将我们的Go语言的一个环境变量给它设置过,所以它可能就出现了这样的一个问题。

现在我们可以再将它变化一下,找到我们脚本,编译Go语言WebAssembly的脚本,大概是在build 在这个目录下这个脚本,然后将这个脚本拷贝过来,后面参数要改一下,把这个off改成on,将Go语言的模块化给它启动,启动以后我们再执行,现在就没问题了。这个执行它用了一个小脚本,这个小脚本在我们的目录下里面有一个package.json。在这个文件里面我们看一眼,这个就是我们用的小脚本。这个里面我们还用了一个热加载的技术,它是通过gin这个模块进行实现的,本质上我们后台程序,它是在8080端口启动的,热加载是启动在3000这个端口,在这个端口去启动了。我们访问前端小程序访问,其实现在是通过3000端口然后进行访问的这样的一个程序,这是它的启动方式。

接下来我们再看我们用到的接口都在哪里,在这个controllers里面有一个api,里面有一个home.go,我们现在优化项目里面涉及到的所有的接口都在这个文件里面,现在我们开始去扩展我们接口了,用于计算格式化时间的一个接口。首先我们可以看一下,我们最终源码里边,在6.3.2 server里面api,然后是home,这里面会有一个,我们看一下是不是有一个关于时间格式化字符串的一个接口。不是这个目录,搞错了,应该是6.4.2,6.4是我们这节课的一个标题。然后server controllers,然后api home,这个地方首先有这个时间对象 零点时间对象也是我们接下来需要的主要的方法在这个地方,由毫秒获取消逝的时间,然后进行格式化计算。这是我们的主要的一个代码,将这个代码拷贝一下,然后找到我们目前的项目home,找到以后我们可以把它放在我们的其他的代码的前面。最上面这里面还用到一个zero,zero的话目前还没有,我们需要也将它拿过来,注意这个zero,我们外面还有一个var,这是Go语言的批量声明变量的一种方式,它可以加个小括号,然后同时声明很多的变量,这是Go语言的一种语法。我们将这个给它拷贝过来,到我们的这个文件也采用相似的一种方式,在这个地方,这是type,在这个地方,放在这里。当我们修改这个代码以后,我们可以看到在我们终端,内嵌终端里面,它会自动地加载修改后的代码,重新编译,这就是热加载。

有了热加载的话,我们不需要频繁地手动重启我们的后端程序了,这方便提高我们的研发效率,这个好像没有什么问题,我们看到这样一个绿色的提示,说明自动的编译已经成功了,接下来我们要测试一下我们新添加的接口。怎么样去测试,我们可以用curl来测试。这个是它的一个接口的地址,接口的地址我们简单也提一下,前面这些前面api后面这个,这个信息段它其实是在哪里决定,它其实是在我们它本身被注册的时候我们看一下init.go里面,在这个地方看到没有,这有一个home api在哪里,api是在上级目录,不在这里,在我们routers,init.go,看到没有,这个地方这有个api 在这里注册的,这个地方又注册了一下,然后有home这个节点了,然后再往里面,所以我们接口的地址,它是从我们api home后面开始算的。

名字它是有讲究的,如果我们写是GetFormatedms,这样写的话,前面这个Get相当于是我们HTTP请求,它里面的method,是它的协议里面的方法,后面才是我们的接口。它里面的路径,接口的路径,是这样的一种方式。将这个拷贝一下,打开一个终端,我们用内嵌终端也是可以的一样的,内嵌终端可以同时看我们代码。用curl 如果你机器上没有的话你要先安装一下curl,然后是地址现在我们的这个地址,在localhost 3000这个地方,接下来就可以测试了。这个地方多了一个斜杠把它去掉,然后回车,有个问题对不对,报告了一个问题,为啥要有这个问题,然后我们这个网址也可以放在浏览器里面看,我们放在浏览器里面也可以,因为它是一个Get请求,其实放在浏览器里面也是可以的,然后刷新 再刷新一下,提示没有找到。为啥没有找到,看我们后端有没有报错 没有报错,后端没有报错,然后再刷新一下,看页面里面源码有没有报错。它的返回,这个接口有没有 Network面板可以看一眼,它其实404没有找到。我们其他的接口可以访问吗,我们看一下我们api home,这个是可以访问的吗,这个是可以的,说明地址应该是没问题的。

再看一下我们的接口地址,再确认一下我们这个接口地址,接口地址好像就是这样也没有问题,再重新再访问一下,刚才我们看到我们新添加的接口,然后访问不到,为什么访问不到呢,为什么访问不到,为啥访问不到。首先我们确认一下我们当前的源码执行的目录,我们执行yarn dev指令是在哪里执行的,可以用pwd看一下,我们当前是在这个目录下执行的对不对,这个目录不对,因为我们很多后端实例代码都是类似的,所以很容易搞混,在我们当前的项目目录下面1下面然后有server,然后在这个地方打开集成终端,打开以后用yarn dev进行启动,启动完成以后开始用curl进行测试,curl我们测试的时候上面有一个示例的写法是可以复用的,然后前面这个我们可以拷贝一下,找到一个地方有问题,刚才启动的时候它说这个端口已经被占用了。我们看一下是不是其他地方,这个地方前面已经启动,所以它被端口占用了,我们把这个停掉之后,现在可以启动了,将这个文本我们拷贝一下方便我们在终端里面进行测试,这是前面的一页文本,接下来再拷贝一下我们要测试的接口的一个地址 ,就是后面的这部分 拿这个然后粘到后面去,然后回车,把地址拷贝一下,然后放在我们的浏览器里面再刷新一下,第一次执行的时候它没有结果返回,然后第二次有了 为啥,因为我们的后端有热加载的一个机制,就是你第一次请求发过来的时候,它其实当时工作的是3000端口的gin的壳的程序在起作用,内部的8080那个程序其实现在还没有准备好,所以你第一次发请求过来,相当于是将内部的程序给它激活 激活完成以后,再次刷新就没有这个问题了,这种情况也只限于我们使用了,在后端使用了热加载这种机制以后,它才会出现这种问题,实际上线部署的程序它是没有这种问题的。

下面我们再看一下前面的使用curl进行测试,原理上来讲,浏览器里面可以访问用curl模拟网站的请求,它也是可以访问的 对不对,是我们的地址写的不对吗,将我们这个地址可以开一个终端,然后在这个终端里面进行访问,可以测试,这个没有 我们可以再测一下另外的一个地址,首页没问题,这个不行对不对,刚才我们看到我们使用curl在我们集成终端里面进行测试,发现提示no matches found,没有匹配,假如我们把后面的这个给它去掉,你发现又可以了 为什么,其实跟我们写法有关系,这个地址我们如果加了URL参数以后,需要用引号给它引起来,引起来以后访问的结果就正常了,跟我们在浏览器里面看到的结果就一样了,这个测试地址我们其实可以保留下来,它是可以复用的,类似的我们都可以这样去测试,如果是URL里面要有参数的话加个引号就可以了 ,像下面这些都不需要加,它是没有问题的,这个代码演示我们就说到这里。


下面我们自定义实现组件,stopwatch_nw组件。

这个组件的JS代码也使用了这个异步转同步的一个编程范式,和调用Go语言的这个wasm文件一样,我们并不能确定结果它什么时候返回,所以也一定要用到一个flag变量用来平衡网络调用的效率,避免出现刚刚发出的一个请求 数据还没有回来又有新请求发出去的这样的一种情况出现,如果同时有很多用户这样做的话,这种情况其实就相当于我们产品自己的用户对我们自己的服务器发起了一次DDoS攻击,也就是分布式拒绝服务攻击了,这样的一种攻击源自软件本身设计的一个缺陷,实在是不应该出现的,如果网络带宽可以的话,从后台调用其实并不一定比本地调用Go语言的WebAssembly文件,或者是调用worker线程更慢,全部完成以后我们可以看到执行结果,单击组件本身可以切换运行的状态,运行效果和原来基本上还是一致的

下面我们进行代码演示。

打开我们的微信开发者工具,首先要明确一下我们新的组件要放在我们的index_addons这个目录下面,这个里面其实已经有了 我们可以看一下,stopwatch_nw,这就是我们调用后端接口的秒表组件,nw代表是network,样式代码和标签代码和之前都是一样的,然后我们重点看JS代码里边有什么变化,组件的属性、数据对象这些都没有变化,stop也没有什么变化,switch没有变化,主要在start这个方法里面,这个方法里面可以看到convertTimeStampToString这个方法里面是用了一个箭头函数,箭头函数然后赋值给了它在这个里边我们调了我们的接口,用promisify然后用了异步转同步的这种方式,转完以后调到我们接口,同时将我们ts作为参数传给了它,拿到这个结果以后去调用setData进行设置,这是我们的一个代码,和之前我们优化一样self我们是可以去掉的,我们将self给它去掉,不需要,可以搜索一下看看有没有 没有其他代码使用它了,然后这个地方仍然是有一个flag,用于平衡我们网络调用,避免网络请求产生拥堵的一个现象,这个代码已经改完了 组件代码已经改完了。

接下来我们要看一下我们调用代码,在主页的配置文件里面引用组件的这个地方,将这个wk改成nw,改完以后单击编译按钮测试一下它的表现。这个时候我们就可以看什么,我们就不看Memory面板了,要看Network这个面板,在这个里边当我们启动组件的时候,正常情况下它应该向后端不停地发送网络请求,调用接口然后取得结果,样式没有显示出来,再刷新一下,怎么样式还没有显示出来,这种情况我们可以清一下编译缓存再单击编译,好 现在已经显示了,打开Network面板将目前的内容清除一下,然后单击开始,我们可以看到这个地方是不是有很多调用,现在我们打开Performance面板看一下它的执行性能,单击开始 然后开始录制,然后停止,好 看一下它的执行性能,总体而言没有红色的倒三角,一般而言 我们以为我们通过后端接口调用,它的效率可能会比较差,但其实我们看到实际的情况还没有那么糟糕,没有倒三角,花费的时间我们可以看一下这个大概是40ms,然后这个是45ms,一般在30 40这样的一个ms的一个消耗相对是比较正常的,如果达到了60 70的话,它一般就会出现红色的一个倒三角提示了,这个代码演示就到这里。


最后我们总结一下,有一种游戏叫云游戏,整个游戏的内容都是在服务器端完成渲染并通过网络向客户端传输的,如果你在科技大会的展台玩过这种游戏的话,你会发现它的性能其实并不像我们想象的那样糟糕,甚至如果这个工作人员不告诉你这是云游戏的话,是在云端运行的话你可能还会误以为,它就是在本地运行的,小游戏代码包小,视图代码在WebView里面执行,它适合做一些小而轻的一些展示,不太适合做一些大数据量的一些运算,如果是你的小程序产品涉及到这方面的一些运算 大数据的运算,那不妨我们将这样的一些运算逻辑放在服务器端,一般情况下大多数小程序它都不需要这样做。这节课我们其实只是给你一个展示 一个示范,像格式化时间字符串这样的一个小需求,其实它是不值得我们放在后端通过调用接口这样的一种方式去实现的,这节课我们就讲到这里。


这节课我们主要学习了如何通过运算代码后移,由前端移到后端进行计算,减轻前端页面的一个计算渲染压力。那下节课我们学习如何使用数据缓存。

最后我们看一下思考题。这里有一个问题请你思考一下,在小程序接口里面,一般以Sync结尾的接口,它是同步接口,反之就是异步接口,由于历史原因有几个接口,例如像wx.getSystemInfo还有wx.getStorage和wx.setStorage,这些接口它们虽然没有Sync后缀,但其实它们仍然是同步接口,它们的执行仍然会阻塞主线程的一个进程的进展,在这个小程序里面,经常会在启动阶段就需要拉取系统信息,例如像屏幕的高度、屏幕的分辨率等等这些信息,那么开发者有什么样的一种办法,可以既不阻塞主线程的一个执行又能拿到我们想要的这些系统信息呢?还有有没有一种办法将wx.getSystemInfoSync这样的一个同步接口改成这样异步接口,从而让同步的代码调用不需要占用时间,但是有一点我们需要注意就是wx.getSystemInfoSync接口,它这个方法不能像操作对象属性那样直接进行改写,在小程序里面是不允许这样做的。这个问题先留给你思考一下,下节课我们来一起深入探讨一下这个问题。

最后一次编辑于  2022-07-14
赞 1
收藏

1 个评论

  • xgqfrms
    xgqfrms
    2022-08-26

    本地跑不起来呀, go 依赖报错安装了,还是不行

    `go get -u github.com/gin-gonic/gin`


    2022-08-26
    赞同 1
    回复
登录 后发表内容

小程序性能优化实践

课程标签