河南地区微商城优化外包服务费用是多少?

摘要:微盟微商城收费标准,河南网站优化外包服务,网站维护是什么职业,网站开发语言 排行榜GaiaX跨端模板引擎,是在阿里优酷、淘票票、大麦内广泛使用的Native动态化方案,其核心优势是
微盟微商城收费标准,河南网站优化外包服务,网站维护是什么职业,网站开发语言 排行榜GaiaX跨端模板引擎#xff0c;是在阿里优酷、淘票票、大麦内广泛使用的Native动态化方案#xff0c;其核心优势是性能、稳定和易用。本系列文章《GaiaX开源解读》#xff0c;带大家看看过去三年GaiaX的发展过程。 前言 GaiaX【https://github.com/alibaba/GaiaX】是由优酷应… GaiaX跨端模板引擎是在阿里优酷、淘票票、大麦内广泛使用的Native动态化方案其核心优势是性能、稳定和易用。本系列文章《GaiaX开源解读》带大家看看过去三年GaiaX的发展过程。 前言 GaiaX【https://github.com/alibaba/GaiaX】是由优酷应用中心技术团队研发的一款跨端高性能渲染引擎目前该方案已经向技术社区开源其核心目标是解决多端卡片化UI组件的研发效能问题。 先看一下GaiaX构建的总体链路 图 - GaiaX构建总体链路 可以看到在 GaiaX 中从结构化的模板文件到端渲染经过了模板解析、节点树构建、视图树构建、表达式运算、扩展交互等步骤。 本文主要将主要从表达式的方案设计、语法树构建以及表达式的跨平台实现这几个方面对表达式运算这个模块进行介绍。 表达式介绍 在GaiaX模板的构建过程中表达式是较为重要的一个模块其主要的能力是对数据进行取值或运算并绑定到对应的视图中它作为逻辑动态化的基础承接着上层业务对视图数据绑定的具体描述视图的数据变化和具体表述均由表达式作为纽带。 {data:{gx-expression-value:{value: $data.text},gx-expression-calculate:{value: 12*3%3$data.num},gx-expression-function:{value: Size($data.array)}} }在表达式中我们支持取值运算、函数计算以及表达式运算的能力为了实现双端一致性我们使用了C作为表达式的底层开发语言。 技术方案设计 表达式的解析过程 图 - 表达式各端解析流程 表达式的解析过程其实就是编译的过程编译即把通过源语言编写成的源程序转化为目标程序的过程通常编译的完整流程是把源程序通过词法分析、语法分析、语义分析、中间代码生成等步骤生成计算机可以理解的机器语言考虑到GaiaX的表达式的作用范围我们只考虑前半部分即词法分析、语法分析以及语义分析。 我们先通过一个简单的流程图了解一下表达式的整个解析流程 词法分析 词法分析是对表达式输入的字符流进行扫描根据对应的构词规则对每个词进行划分和分类将其组成有意义的词素序列。 语法分析 语法分析是在词法分析的基础上将词法分析生成的词素组成各类语法短语并判断表达式在结构上是否正确最终构建出符合语法规则的语法树以及对应的符号表。 语义分析 语义分析则是结合语法分析中生成的语法树和符号表对输入的表达式的语义规则进行分析判断语义是否符合规则。 在GaiaX表达式中我们使用LR(1)文法进行语法分析并构建语法树并将语法分析和语义分析结合起来即在语法树的构建过程中判断表达式是否符合语义规则并在语法树构建完成后返回最终的结果。 语法树的构建 - LR(1)文法 上文说到表达式的解析过程其实就是一个编译的过程。在GaiaX表达式方案中我们采用了编译原理中经典的LR(1)文法作为表达式语法树的构建方案。 LR(k)分析方法是1965年Knuth提出的,括号中的k表示向右查看输入事符号的个数。这种方法比起自顶向下的LL(k)分析方法和自底向上的优先分析方法对文法的限制要少得多也就是说,对于大多数用无二义性上下文无关文法描述的语有都可以用相定的LR分析器进行识别而且这种方法还具有分析速度快能准确即时地指出出错位置的特点。 LR(1)文法 LR(1)文法的意思是从左向右扫描最右推导往前多看一个字符。 字符含义L从左到右扫描输入串R利用最右分析方法来识别句子(1)向右展望1个字符 在具体介绍LR(1)分析法之前我们需要先了解两个基本概念 名称含义推导一个字符串x通过一个规则变换成另一个字符串y称为x推导出y即x-y规约与推导相反语法规则为x-y时由y规约到x即为规约 GaiaX表达式语法树构建流程 LR(1)的分析过程是规约的过程我们以GaiaX表达式中的运算语法为例深入了解GaiaX表达式语法树的构建流程。 在GaiaX表达式中四则运算的语法如下 S - S E #加|S - E #减|E E - E * num #乘|E / num #除|num假设我们有表达式a*bc 在这个表达式中我们可以看到乘法的优先级是要大于加法的那么在LR(1)文法中我们应该怎么去撰写我们的语法使得乘法的优先级要大于加法呢 在前文中我们了解到推导是从上往下一直推导出整个式子而LR(1)文法是规约的过程规约与推导相反是从下往上从底部一直推到到根部节点的过程根据这点我们可以了解到在LR(1)文法中语法的推导层级越深那么就会越先被运算它的优先级就越高。 所以在GaiaX的四则运算语法中我们让乘除法的层级在加减法之下从而实现乘除法的优先级大于加减法的优先级。 语法树的构建流程 在确认了具体的语法之后我们就可以根据语法去构建具体的语法树了我们先来看一下语法树的构建流程 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mLZeGZcM-1676431808557)(/img/bVc6nAj)] 图 - 语法树构建流程 在初始化以及词法分析流程后得到了分析表和词素序列接下来我们通过不断把词素入栈并匹配判断是否可以规约来构建最终的语法树。 示例的语法树构建流程如下 步骤栈输入说明1nullnum*numnum表达式输入2num*numnum移进3num*numnum移进4Enum移进num*num规约为E5Enum移进6Snull移进Enum规约为S分析成功 在一步步移进和规约的过程中当规约到最后的根结点时便生成了一棵完整的语法树如下图所示可以看到乘法的优先级更高所以离根节点越远加法的优先级较乘法低离根节点越近。 图 - 示例语法树 跨平台实现方案设计 在前文中我们简要介绍了GaiaX表达式各端调用的链路流程我们了解到表达式的计算能力可以被Android、iOS端所调用接下来我们来了解一下GaiaX表达式跨平台能力的实现。 C层调用各端取值与方法函数 在跨平台方案中主要涉及两种情况 第一种情况是双端调用C层的方法在iOS端我们可以直接通过添加头文件引用直接调用C函数而在Android端我们则需要使用中间层JNI来间接调用C层的代码。 第二种情况则是C层调用双端实现的方法相较于端侧调用C的代码由C层调用端侧实现的方法会更为复杂我们先来看一下C层调用端侧代码的大致链路 图 - 双端取值和函数方法的调用与实现 由流程图我们可以看出C层调用Android以及iOS端的数据获取和函数调用方法都是需要双端进行实现的要达到双端实现C层能够调用的方法我们需要先在C层定义GXAnalyze类并提供对应的方法虚函数。 class GXAnalyze {public://获取数据 $virtual long getSourceValue(string valuePath, void* source) 0;//获取方法 Functionvirtual longgetFunctionValue(string funName, long *paramPointers, int paramsSize, void* source) 0; }C调用Android端方法的实现 在Android端中为了实现C提供的虚函数并返回给C层调用我们创建了GXAnalyzeAndroid类并在类中创建出对应的取值和方法调用接口。 class GXAnalyzeAndroid {// 计算逻辑的扩展interface IComputeExtend {// Computed value expressionfun computeValueExpression(valuePath: String, source: Any?): Long// Computed function expressionfun computeFunctionExpression(functionName: String, params: LongArray): Long}init {initNative(this) //初始化表达式并存储GXAnalyzeAndroid对象} }在JNI层我们实现了两个方法分别是getSourceValueFromJava取值方法调用以及getFunctionValueFromJava函数方法调用以getSourceValueFromJava为例我们通过获取在initNative时存储的GXAnalyzeAndroid对象通过CallLongMethod调用其实现的取值方法。 object_ininitNative时存储的GXAnalyzeAndroid对象 static jlong getSourceValueFromJava(string valuePath, jobject source, jobject object_in) {JNIEnv *env getJNIEnv(); //获取环境env变量if (env ! nullptr) {jclass clazz;clazz env-GetObjectClass(object_in);jfieldID analyze_fieldID env-GetFieldID(clazz, computeExtend,Lcom/expressionDir/GXAnalyzeAndroid$IComputeExtend;);jobject jobject env-GetObjectField(object_in, analyze_fieldID);jclass analyzeJni env-GetObjectClass(jobject);jmethodID getArrId env-GetMethodID(analyzeJni, computeValueExpression,(Ljava/lang/String;Ljava/lang/Object;)J);jlong res env-CallLongMethod(jobject, getArrId,str2jstring(env, valuePath.c_str()),source);env-DeleteLocalRef(clazz);env-DeleteLocalRef(jobject);env-DeleteLocalRef(analyzeJni);return res;}return 0L; } 需要注意的是仅仅实现了JNI调用Java\Kotlin的方法还不足以实现在C层调用Android端的代码我们在JNI层在实现调用解析表达式的函数的同时通过继承的方式实现了GXAnalyze类的虚函数。 class GXJniAnalyze : public GXAnalyze {public:long getSourceValue(string valuePath, void *source) override {jobject dataSource static_castjobject(source);return getSourceValueFromJava(valuePath, dataSource, globalSelf);} }; extern C JNIEXPORT jlong JNICALL Java_com_alibaba_gaiax_analyze_GXAnalyze_getResultNative(JNIEnv *env, jobject thiz, jobject self,jstring expression, jobject data) {GXJniAnalyze *jAnalyze getJniAnalyze(env, self);long res jAnalyze-getExpressionResult(jstring2str(env, expression), data);return (jlong) (res); }这样我们在调用表达式解析的方法时实际上调用的是继承自GXAnalyze并实现虚函数后的GXJniAnalyze里的getExpressionResult方法在C层我们在调用取值或函数方法时只需要使用this-getSourceValue(string,void*)就能调用在端侧实现了的虚函数根据端侧的逻辑返回我们需要的结果。 C调用iOS端方法的实现 在iOS端中为了实现C提供的虚函数并返回给C层调用我们首先实现了GXAnalyzeBridge类并在其中对取值以及函数调用方法进行了实现。 interface GXAnalyzeBridge : NSObject- (long)getFunctionValue:(NSString *)funName paramPointers:(long *)paramPointers paramsSize:(int)paramsSize;- (long)getSourceValue:(NSString *)valuePath source:(id)source;end紧接着我们创建出了GXAnalyze的继承类GXAnalyzeImpl在类中我们重写了函数以及取值调用方法在方法中通过调用中间层GXAnalyzeBridge的具体实现方法达到取值以及函数能力的实现。 class GXAnalyzeImpl: public GXAnalyze {public: //解析取值 long getSourceValue(string valuePath, void* source);//解析方法 long getFunctionValue(string funName, long *paramPointers, int paramsSize, string source);};最终在C层我们在调用表达式的取值或函数方法时实际上调用的是在iOS端已经实现了的继承类GXAnalyzeImpl里对应的方法。 统一数据类型 在GaiaX表达式中会有端侧调用C层的方法和C层调用端侧这两种情况但是各端的数据类型是不一致的而且在表达式的计算过程中每个数据的类型也是不一致的为了能够实现一套数据类型我们实现了GXValue数据类在各端可以通过调用GXValue的多个数据创建方法创建对应类型的数据作为结果返回即可。 class GXValue { public:int64_t tag;int32_t int32; //Bool 10float float64; //Floatint64_t intNum; //longvoid *ptr; //Array,Mapchar *str; //String };成果展示 图 - GaiaStudio表达式编辑运算 性能及稳定性保障 质量保障 由于采用了跨平台技术方案因此稳定性保障是项目的重中之重。 在项目交付过程中针对不同复杂度、取值类型进行了充分的单元测试用例设计尽可能覆盖线上可能出现的各种边界异常情况。 图 - 单元测试用例 性能分析 由于技术方案底层由C实现因此基础性能表现是有保障的。 计算类型表达式耗时/次单值100000.017ms取值$data.xxx0.024ms取数据源$$0.019ms数值运算10%50.029ms三元表达式true ? 1 : 20.048ms函数计算Size(‘1000’)0.029ms复杂嵌套表达式$data.b % 5 2 ? $data.b % 5 : 10.060ms 表 - Android端真机测试性能结果 总结 GaiaX表达式充分吸收了编译原理的精髓通过跨平台技术方案从根本上保证了多端的一致性问题为GaiaX在移动平台的落地提供了较高的可扩展性。目前来看该方案在性能方面还有一定的优化空间如规约算法、词法分析、数据结构等方面的优化这也是我们后续重要的发力点。 跨端表达式方案目前已经在GaiaX开源项目(https://github.com/alibaba/GaiaX)中发布非常欢迎广大技术爱好者一起探讨交流。 GaiaX开源解读系列文章 系列文章持续更新中请各位拭目以待 • 《GaiaX开源解读 | 基于优酷业务特色的跨平台技术》 • 《GaiaX开源解读 | 跨端动态化模板引擎详解看完你也能写一个》 • 《GaiaX开源解读 | 给StretchRust编写的Flexbox布局引擎新增特性我掉了好多头发》 • 《GaiaX开源解读 | 表达式作为逻辑动态化的基础我们是如何设计的》 • 《GaiaX开源解读 | 向经典致敬 ReactNaitve与GaiaX渲染核心技术分析》 • 《GaiaX开源解读 | 为了保障双端一致性我们做了哪些努力》 • 《GaiaX开源解读 | 一条龙的模板研发体系你不来看看么》