• PCB 规则引擎之脚本语言JavaScript应用评测


    世界上没有好做的软件,觉得好做,只是你的系统简单而已,而不是哪个行业简单,特别像我们PCB制造企业务逻辑的很复杂的,仅仅靠决策树中的每个节点布置决策逻辑是不能满足要求的,所以我们在制作PCB规则引擎必须再向更高一层次考虑,让规则管理灵活度更高,控制力度更大的决策逻辑组件。当然一个好的规则引擎对脚本语言的支持是必不可少的,如何选择脚本语言是规则引擎选型非常重要一环,需要考虑,用户对脚本的易学,易用,脚本的性能,脚本语言与.net语言深度交互能力,

    写了一个工具专用于对JS进行测试,语法支持,性能,交互性进行测试.

    一.基本语法测试

            1. 检测流程是否存在

    var ppeflow =new Array('开料','钻孔','沉铜','板镀','干膜','图形电镀','退膜','蚀刻','退锡','阻焊','字符','喷锡','铣板','测试','终检');
    if (ppeflow.exists ("开料"))
    { 
        console.alert('存在');
    }
    else
    { 
        console.alert('不存在');
    }
    /*
    判断数组中是否存在
    */
    Array.prototype.exists = function (val) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] == val) {
                return true;
            }
        }
        return false;
    }

            2 检测流程顺序

    //查找制定元素在数组中的索引值
    Array.prototype.indexVf=function(arr){
        for(var i=0;i<this.length;i++){
            if(this[i]==arr){
                return i;
            } 
        }
    }
    var ppeflow =new Array('开料','钻孔','沉铜','板镀','干膜','图形电镀','退膜','蚀刻','退锡','阻焊','字符','喷锡','铣板','测试','终检');
    var index1 = ppeflow.indexVf('字符');
    var index2 = ppeflow.indexVf('喷锡');
    if (index1< index2)
    { 
        console.alert('字符在喷锡前');
    }
    else
    { 
        console.alert('字符在喷锡后');
    }

            3 判断孔径比值

    var holesize = 0.2;
    var thick = 2.5;
    //判断孔径比是否大于12:1
    var scale = thick / holesize;
    if (scale > 12)
    { 
        console.alert('孔径比值大于12');
    }
    else
    { 
        console.alert('孔径比值小于或等于12');
    }

            4 判断客户代码等于T001

    var pdctno = 'at00101ca0'; //客户代码在生产型号中间2到5位
    pdctno = pdctno.toUpperCase(); //转为大写
    var custcode = pdctno.substr(1,4); 
    if (custcode == 'T001')
    { 
        console.alert('客户代码等于T001');
    }
    else
    { 
        console.alert('客户代码不等于T001');
    }

            5 求钻孔表总孔数

    var drlTable = [
    {'HoleType':'PTH','HoleSize':3.175,'HoleCount':5,'DisplayOrd':0},
    {'HoleType':'PTH','HoleSize':0.2,'HoleCount':15,'DisplayOrd':1},
    {'HoleType':'PTH','HoleSize':0.3,'HoleCount':52,'DisplayOrd':2},
    {'HoleType':'PTH','HoleSize':1.0,'HoleCount':44,'DisplayOrd':3},
    {'HoleType':'PTH','HoleSize':2.0,'HoleCount':11,'DisplayOrd':4},
    {'HoleType':'PTH','HoleSize':3.5,'HoleCount':20,'DisplayOrd':5},
    {'HoleType':'PTH','HoleSize':4.0,'HoleCount':18,'DisplayOrd':6}
    ];
    var HoleCount = 0;
    for(var i in drlTable)
    { 
        HoleCount += drlTable[i].HoleCount ;
    }
    console.alert('总孔数:' + HoleCount) ;

            6 板厚喷锡板尺寸判断

     /*
    判断数组中是否存在
    */
    Array.prototype.exists = function (val) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] == val) {
                return true;
            }
        }
        return false;
    }
    var thick = 0.4;
    var surface = '喷锡';
    var pnlwidth = 18;
    var pnlheight = 24;
    //判断当板厚<=0.5mm,表面处理为喷锡时,PNL尺寸不能大于16X18
    if (thick < 0.5 &&  ['喷锡','有铅喷锡','无铅喷锡'].exists(surface) )
    { 
        if (pnlwidth > 16 || pnlheight > 18)
        { 
            console.alert('板厚<=0.5mm,表面处理为喷锡时,PNL尺寸不能大于16X18');
        }
    }
    else
    { 
        console.alert('PNL尺寸符合要求');
    }

       小结:通过实际PCB工程基本检测规则对JS语法验证,选用JS语言作为PCB工程客户端进行规则维护还不错哦!JS语法友好,易学,易用。

    二.性能测试

       1.JS循环1亿次  耗时839毫秒

    var sum = 0;
    for (var i=0; i<100000000; i++)
    {
          sum ++;
    }

       2.C#外循环1000次,JS内循环10W次 合计1亿次  耗时3222毫秒

    var sum = 0;
    for (var i=0; i<100000; i++)
    {
        sum ++;
    }

       3.JS调函数循环1亿次  耗时8416毫秒

    var sum = 0;
    for (var i=0; i<100000000; i++)
    {
        var rndNum = Math.ceil(Math.random() * 10); 
        sum += sumsxi(rndNum,i);
    }
    function sumsxi(a,b)
    { 
        return a + b; 
    }

       4.C#外循环1000次, JS调用函数内循环10W次 合计1亿次  耗时17305毫秒

    var sum = 0;
    for (var i=0; i<100000; i++)
    {
        var rndNum = Math.ceil(Math.random() * 10); 
        sum += sumsxi(rndNum,i);
    }
    function sumsxi(a,b)
    { 
        return a + b; 
    }

    小结:通过以上测试:脚本语言能达到这个速度水平非常棒了,我们来看看这个速度是否能满足实际要求呢,

    通常执行一次JS V8引擎实例化一次就好了(即在C#中执行),第一次将,列表数据,对象数据,C#函数,JS函数装载进去后,接着规则引擎主要耗时将在执行脚本上面了,比如:一个规则数结构最多按100个节点,应该足够了,然后每个节点存在JS可执行代码1000行,考虑到实际更复杂,将1000行代码复杂度乘以10倍,那么这里按1W行的代码量计算;100个节点乘以1W行代码量,就是100W行代码量,实测耗时:100毫秒。这个速度顶呱呱的.

    但实际应用中还待验证(比如多用并发,更复杂的业务逻辑超耗时,大量数据(10M数据量)进入JS规则引擎参与到数据引用与计算).

     

    三.交互性测试(JS内置对象返回)

          把业务逻辑用JS脚本写,并用JS V8引擎执行脚本, 并将计算结果返回给C#

          测试:JS脚本中的内置对象,如:单个值,对象,数组 类型,进行业务逻辑处理后并将对象变量返回给C#

          1.JS内置单值

              例1:计算孔径比

    //计算孔径比值
    var holesize = 0.2;
    var thick = 2.5;
    var scale = thick / holesize;
    scale;

              例2:通过表面处理ID号找到对应的表面处理名称  

    var arr =[ ['喷锡','A01'],['沉金','A02'],['OSP','A03'],['镀金','A04'],['沉银','A05'],['沉锡','A06']] ;
    var SurfaceCode = 'A03';  //表面处理ID号
    var SurfaceName = '';        //通过ID号找到对应的表面处理名称
    for(var i in arr)
    { 
        if (techno == arr[i][1])
        { 
            SurfaceName = arr[i][0];
        }
    }
    console.log(SurfaceName) 
    SurfaceName

     

           2.JS内置对象

              JS对象返回给C#类型转为:字典Dictionary<string,Object>类型

            例3:将JS中的钻孔对象返回给C#

    var HoleMod = { 'HoleType':'PTH','HoleSize':0.2,'DisplayOrd':1};
    HoleMod.HoleCount =  22;
    HoleMod

     

           3.JS内置数组

              JS 数组返回给C#类型转为:Object[]类型

            例4:将JS中的钻孔表数组返回给C#

    var drlTable = [
    {'HoleType':'PTH','HoleSize':3.175,'HoleCount':5,'DisplayOrd':0},
    {'HoleType':'PTH','HoleSize':0.2,'HoleCount':15,'DisplayOrd':1},
    {'HoleType':'PTH','HoleSize':0.3,'HoleCount':52,'DisplayOrd':2},
    {'HoleType':'PTH','HoleSize':1.0,'HoleCount':44,'DisplayOrd':3},
    {'HoleType':'PTH','HoleSize':2.0,'HoleCount':11,'DisplayOrd':4},
    {'HoleType':'PTH','HoleSize':3.5,'HoleCount':20,'DisplayOrd':5},
    {'HoleType':'PTH','HoleSize':4.0,'HoleCount':18,'DisplayOrd':6}
    ];
    drlTable;

     

             例5:将JS中的表面处理数组返回给C#

    var arr = ['OSP','沉金','喷锡'];
    arr[6] = '沉锡';
    arr;

           4.JS内置函数

            例6:在JS中写函数并在JS中调用应,   此函数不能返回给C#

    //计算孔径比JS函数
    function HoleSizeThickSclae(HoleSize,Thick)
    { 
        return  Thick/HoleSize;
    }
    
    var holesize = 0.2;
    var thick = 2.5;
    HoleSizeThickSclae(holesize,thick);

     四.交互性测试(C#传参与返回)

          把业务逻辑用JS脚本写,用JS V8引擎执行脚本, 并将计算结果返回给C#

          测试:将C#中的对象变量传给JS脚本,如:单个值,对象,数组,字典 等类型,JS脚本接受此类型数据后进行业务逻辑处理,处理完成后,再将对象变量返回给C#.

          1.C#传入单值

               C#传入数据:

                string str1 = "样板";
                int num1 = 2018;

                 JS接受数据并处理,返回单个值

    //原始C# 单个值输出
    console.log(num1);
    console.log(str1);
    console.log('=================');
    //更改C# 单个值
    num1 += 10
    str1 =  '钻孔' + num1.toString();
    //更改后C#对象值输出
    console.log(num1);
    console.log(str1);
    console.log('=================');
    //返回给C#
    str1;

           2.C#传入对象

              C#传入数据:

                ppeflow ppeflow = new ppeflow ();
                ppeflow.Num = 1;
                ppeflow.TechName = "开料";

            JS接受数据并处理,返回对象

    //原始C#对象输出
    console.log(ppeflow.Num);
    console.log(ppeflow.TechName);
    //更改C#对象值
    ppeflow.Num = 2
    ppeflow.TechName = '钻孔';
    //更改后C#对象值输出
    console.log(ppeflow.Num);
    console.log(ppeflow.TechName);
    //返回给C#
    ppeflow;

           3.C#传入数组

                C#传入数据:

                List<ppeflow> ppeflowList = new List<ppeflow>()
                {
                    new ppeflow(){ Num = 1, TechName = "开料"},
                    new ppeflow(){ Num = 2, TechName = "钻孔"},
                    new ppeflow(){ Num = 3, TechName = "沉铜"},
                    new ppeflow(){ Num = 3, TechName = "板镀"},
                    new ppeflow(){ Num = 3, TechName = "干膜"},
                    new ppeflow(){ Num = 3, TechName = "图镀"},
                    new ppeflow(){ Num = 3, TechName = "退膜"},
                    new ppeflow(){ Num = 3, TechName = "蚀刻"},
                };

                   JS接受数据并处理,返回数组

    ppeflowList[0].TechName = 'ECN';  //更改0号数组值
    ppeflowList[11] = { "Num":9,"TechName":"FQC"}   //通过JS增加对象 给到11号数组
    ppeflowList[12] = ppeflowList[1]    //将C# 1号数组  赋值给12号数组
    ppeflowList[12] .TechName = '包装'  //修改12号数组值
    for (var i in ppeflowList)
    { 
        console.log(ppeflowList[i].TechName)  //查看数组内容
    }
    ppeflowList; //返回给C#数据

            JS处理后的数组返回给C#的数据变化关系

    4.C#传入字典

                  C#传入数据:

                Dictionary<string, string> dic = new Dictionary<string, string>();
                dic.Add("01", "开料");
                dic.Add("02", "钻孔");
                dic.Add("03", "干膜");

                       JS接受数据并处理,返回字典

    dic['01'] = '流程指示'; //修改C#字典值
    dic['04'] = 'FQC';    //增加字典值
    dic;                  //返回给C# 

           5.C#传入函数

                   C#传入数据:

       calc calc = new calc();
    
        public class calc
        {
            public int sum(int a,int b)
            {
                return a + b;
            }
        }

                  JS调用C#函数,并返回结果

    var aa = 18;
    var bb = 2000;
    var cc = calc.sum(aa,bb); //调用C#函数加算计算
    console.log(cc);
    cc;

     五.JS扩展

           1.扩展函数console 给JS使用

               C#写函数部分

        public class console
        {
            public event EventHandler logHandler;
            /// <summary>
            /// 打印log
            /// </summary>
            /// <param name="msg"></param>
            public void log(object msg)
            {
                if (logHandler != null)
                    logHandler(msg, null);
            }
            /// <summary>
            /// 打印到控制台
            /// </summary>
            /// <param name="msg"></param>
            public void print(string msg)
            {
                Console.WriteLine(msg);
            }
            /// <summary>
            /// 弹窗提示
            /// </summary>
            /// <param name="msg"></param>
            public void alert(string msg)
            {
                MessageBox.Show(msg, "JavaScript提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            /// <summary>
            /// 输入窗
            /// </summary>
            /// <param name="msg">输入框信息</param>
            /// <param name="defVal">默认值</param>
            /// <returns></returns>
            public string prompt(string msg, string defVal = "")
            {
                return Interaction.InputBox(msg, "JavaScript输入", defVal);
            }
            /// <summary>
            /// 确认Yes或No窗口
            /// </summary>
            /// <param name="msg">提示框信息</param>
            /// <returns></returns>
            public bool confirm(string msg)
            {
                DialogResult result = MessageBox.Show(msg, "JavaScript确认", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
                return result == DialogResult.Yes;
            }
        }

                JS调用C#函数

    for (var i=0;i<10;i++){
        console.log('log输出' +i);  
    }
    var cc = 'pcbren 致力于PCB工程自动化研究';
    console.alert(cc);
    var tt = console.prompt('请输入:pcbren ','test');  
    while (tt !='pcbren')// 输入pcbren 否则死循环
    { 
        tt = console.prompt('请输入:pcbren ','test');
    }

                 JS调用C#函数测试界面

           2.扩展函数JSON给JS使用

               C#写函数部分

        public class JSON
        {
            /// <summary>
            /// 对象转Json字符串
            /// </summary>
            /// <param name="Object"></param>
            /// <returns></returns>
            public string stringify(object Object)
            {
                return Newtonsoft.Json.JsonConvert.SerializeObject(Object);
            }
            /// <summary>
            /// Json字符串转对象
            /// </summary>
            /// <param name="StirngJSON"></param>
            /// <returns></returns>
            public object parse(string StirngJSON)
            {
                return Newtonsoft.Json.JsonConvert.DeserializeObject(StirngJSON);
            }
        }

                  JS调用C#函数

    var holeMod = {'HoleType':'PTH','HoleSize':3.175,'HoleCount':5,'DisplayOrd':0};
    var StrJSON  = JSON.stringify(holeMod) ;//转换过程: JS对象==>C#字典==》C#字符串==》JS字符串
    console.log(StrJSON) ;
    
    var Mod = JSON.parse(StrJSON);//转换过程:JS字符串==》C#字符串==>C# JObject对象
    console.log(Mod.ToString()) ;
    
    Mod;

                 JS调用C#函数测试界面

           3.json数据交换与转换

              我们将C#对象数据传递给JS V8引擎,JS脚本可以直接调用C#对象中的属性,如果从C#传入对象Json文本如何处理呢

                 3.1 C#Json字符串传入JS V8后通过JS内置eval 方法转为对象

                      C#代码部份

    string strJSON = "{'Num':1,'TechName':'开料'}";

                     JS转对象部份

    console.log(strJSON);                      //JSON传入JSON字符串
    var obj = eval('(' + strJSON + ')');     //将JSON字符串转为JS对象
    console.log(obj.Num);
    console.log(obj.TechName);

                3.2 C#Json字符串内嵌JS V8 变量为对象如 var = {'加投率:' 1.05};

                      JS代码部份

    var objinput = {'Num':1,'TechName':'开料'};   //这代码码由C#在执行JS 之前内嵌在其中,
                                                //对于用户看不见此行代码,但可以调用此对象
    
    for(var i in objinput) {
         console.log(objinput[i]);
    }

  • 相关阅读:
    免费证书Let’s Encrypt
    kubernetes中使用ServiceAccount创建kubectl config 文件
    kubectl alias auto complete
    kubernetes dashboard permission errors
    du 与df 统计系统磁盘不一致原因与解决方法
    大访问量、高并发网站优化
    React的Sass配置
    转:Zepto的使用以及注意事项
    转: zepto的使用方法
    Extjs4 修改combox中store的数据
  • 原文地址:https://www.cnblogs.com/pcbren/p/9721496.html
Copyright © 2020-2023  润新知