pcbren

世界上没有好做的软件,觉得好做,只是你的系统简单而已,而不是哪个行业简单,特别像我们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]);
}

 

分类:

技术点:

相关文章: