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]);
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM