手机版

基于Node.js的轻量级云功能实现详解

时间:2021-08-21 来源:互联网 编辑:宝哥软件园 浏览:

导言:

在一切都可以云的时代,你的应用甚至不需要服务器。所有主要云服务都提供了云功能。那么,如何用万能的node.js实现它们呢?

1.什么是云功能?

云功能是云服务中诞生的新名词。顾名思义,云功能是在云中(即服务器)执行的功能。每个云功能都是独立的、简单的、单一用途的,执行环境相互隔离。使用云功能时,开发人员只需关注业务代码本身,其他如环境变量、计算资源等则由云服务提供。

二、为什么需要云功能?

程序员说不想买服务器,所以有云服务;程序员说连服务器都不想写,所以有云功能。

无服务器架构

通常我们的应用会有一个后台程序,负责处理各种请求和业务逻辑,一般需要处理网络、数据库等I/O。所谓的无服务器架构意味着除了业务代码之外的所有东西都被交给执行环境。开发者不需要知道服务器是如何运行的,数据库的api是如何调用——的,一切都交给外界,代码写在“温室”里。

法斯

云功能是实现无服务器架构的途径。我们的应用程序将由独立的功能组成,每个功能都是一个小粒度的业务逻辑单元。没有服务器,没有服务器程序,“功能即服务”。

三、如何实现?

由于此实现在CLI工具中应用,并且函数在开发人员的项目文件中声明,因此一般过程如下:

1.函数声明和存储声明

我们的目标是使云函数的声明与一般的js函数没有什么不同:

module.exports=异步函数(CTX){ return ' hahha ' };因为云函数的执行通常伴随着接口的调用,所以它应该能够支持http方法的声明:

module . exports={ method : ' POST ',handler:异步函数(CTX){ return ' hahha ' } };仓库

由于方法的配置,编译时需要引入上述声明文件。此时,处理程序字段是一个函数类型的对象。您可以调用其toString方法来获取字符串类型的函数体:

const f=require('。/func . js ');const方法=f.methodconst body=f . handler . ToString();//async函数(CTX){//返回‘哈哈哈’//}用字符串的函数体,存储非常简单,可以直接存储在数据库中字符串类型的字段中。

2.功能执行

全球资源定位器(Uniform Resource Locator)

如果用于前端调用,每个云函数都需要有对应的url。如果上述声明文件的文件名是云函数的唯一名称,则url可以简单地设计如下:

/f/:funcname构造独立的作用域(强调)

在js世界中,有以下几种方法可以执行字符串类型的函数体:

评估功能新的功能虚拟机模块,那么我应该选择哪一个呢?我们来回顾一下云功能的特点:独立,互不影响,在云端运行。

关键是将每个云功能放在一个独立的范围内执行,无需访问执行环境。因此,最好的选择是nodejs的vm模块。关于本模块的使用,请参考官方文件。

此时,云功能的执行可以分为三个步骤:

从数据库中获取函数体,并构造上下文对象const sandbox={ CTX : { params 3360 CTX }。参数,查询:ctx。查询,body:ctx。请求。尸体。userid: ctx.userid,},promise: null,console : console } VM . create context(沙盒);执行该函数以获得结果

const code=` func=$ { FuncBody };promise=func(CTX);`;vm.runInContext(代码,沙盒);const data=await sandbox.promiseNPM社区的vm2模块改进了vm模块的一些安全缺陷,同样的思路,也可以使用这个模块。

3.引用

虽然原则上云函数应该是相互独立的,但是为了提高灵活性,我们决定支持函数之间的相互引用,也就是我们可以在一个云函数中调用另一个云函数。

声明

很简单,只需添加一个函数名的数组字段:

module . exports={ method : ' POST ',use: ['func1 ',' func2'],handler:异步函数(CTX){ return ' hahha ' } };注射

也很简单,根据依赖链找出所有的函数,只需要挂载在ctx下,优先考虑深度或者广度。

if(func . use){ const func={ };const fnames=func.usefor(设I=0;i fnames.lengthI){ const fname=fnames[I];wait getUsedFuncs(ctx,fname,funcs);} const FuncCode=` { $ { object . keys(funcs))。map(fname=` $ { fname } : $ { funcs[fname]} `)。join(' \ n ')} `;code=` CTX . methods=$ { FuncCode };$[code]`;} else { code=`ctx.methods={ }$[code]`;}//获取所有依赖函数const getusedfuncs=async (CTX,funcname,methods)={ const func=getfunc(funcname);methods[Funcname]=func . body;if(func . use){ const uses=func . use . split(',');for(设I=0;长度;I){ wait getused funcs(CTX,使用[i],方法);}}}依赖循环

既然可以相互依赖,那么必然会出现abca的依赖循环,所以我们需要在开发人员提交云函数时检测依赖循环。

检测的思路也很简单。在遍历依赖链的过程中,每一条链都被记录下来。如果发现当前遍历的函数已经出现在链中,就会出现循环。

const FuncMap={ };flist . foreach((f)={ FuncMap[f . name]=f;});const chain=[];flist . foreach((f)={ getUseChain(f,chain);});函数getusechain (f,chain) {if (chain。includes(f . name)){ throwner error(`该函数具有循环依赖关系:${[.chain,f.name]。join('')} `);} else { f . use . foreach((fname)={ getUseChain(Funcmap[fname],[.chain,f . name]);});}}4.表演

在上述方案中,每次执行云功能时,都需要执行以下步骤:

获取函数体编译代码构造的范围,在独立的环境中执行步骤3。由于每次执行的参数不同,会有不同的请求并发执行同一个函数,所以作用域ctx不能重用;步骤4是必须的,所以只剩下1和2个可优化点。

代码缓存

vm模块为代码编译和执行的单独处理提供了一个接口,因此每次获得函数体字符串时,它都被编译成一个Script对象:

//.获取codeconst脚本=新虚拟机。脚本(代码);执行时,可以直接传入编译后的Script对象:

//.获取沙盒vm.createContext(沙盒);script.runInContext(沙盒);const data=await sandbox.promise函数体缓存

简单的缓存,没有复杂的更新机制,设置一个时间阈值,拉一个新的函数体,编译得到一个Script对象,然后缓存:

const cacheFuncs={ };//.get script cachefuncs[funcName]={ updatetime : date . now(),脚本,};//缓存时间: 60秒const cacheFunc=cacheFuncs[cacheKey];if(cacheFunc(date . now()-cacheFunc . updatetime)=60000){ const sandbox={/*.*/} vm.createContext(沙盒);cacheFunc.script.runInContext(沙盒);const data=wait saandbox . promise;返回数据;} else {//续订缓存}以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。

版权声明:基于Node.js的轻量级云功能实现详解是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。