NanUI文档目录。一不小心便错使用了任何for循环的跟踪变量。

NanUI文档目录

 前面的语句

  用循环语句迭代数据时,必须使初始化一个变量来记录每一样蹩脚迭代在数量集合中之职,而以许多编程语言中,已经上马通过程序化的方因此迭代器对象回来迭代过程中聚集的各级一个因素

  迭代器的施用可以大幅度地简化数据操作,于是ES6吗向JS中上加了这迭代器特性。新的数组方法与初的聚合类型(如Set集合与Map集合)都指迭代器的贯彻,这个新特征对速之多少处理而言是必不可少的,在言语的其它特色中也都发出迭代器的身影:新的for-of循环、展开运算符(…),甚至并异步编程都足以采用迭代器

  本文将详细介绍ES6饱受的迭代器(Iterator)和生成器(Generator)

 

  • NanUI简介
  • 起采取NanUI
  • 包并动用内嵌式的HTML/CSS/JS资源
  • 行使网页来规划总体窗口
  • 何以贯彻C#跟Javascript的互相通信
  • 哪些处理NanUI中的下载过程 – DonwloadHandler的利用(待更新。。。)
  • 怎处理NanUI中的弹窗过程 – LifeSpanHandler的行使(待更新。。。)
  • 哪决定Javascript对话框 – JsDialogHandler的以(待更新。。。)
  • 起定义资源处理程序 (待更新。。。)

引入

  下面是同段子正式的for循环代码,通过变量i来跟colors数组的目录,循环每次执行时,如果i小于数组长度len则加1,并履行下一致涂鸦巡回

var colors = ["red", "green", "blue"];
for (var i = 0, len = colors.length; i < len; i++) {
    console.log(colors[i]);
}

  虽然循环语句语法简单,但若以多只巡回嵌套则要追踪多个变量,代码复杂度会大大增加,一不小心便不当使用了任何for循环的跟踪变量,从而致使程序出错。迭代器的起旨在铲除这种复杂并缩减循环中之失实

 

什么实现C#及Javascript的互通信

经过事先的文章,相信您已针对性NanUI有矣起的询问。但顶目前为止,我们以NanUI仅仅只是作为呈现HTML界面的容器,并未涉嫌CEF与C#里面数的彼此。那么本文将略介绍如何以NanUI中使用C#调用Javascript的函数和如何在Javascript注入C#的靶子、属性和艺术。

迭代器

  迭代器是千篇一律栽异常对象,它拥有局部特意为迭代历程规划的专有接口,所有的迭代器对象都出一个next()方法,每次调用都回一个结出对象。结果对象来半点独特性:一个凡是value,表示产一个将要返回的价值;另一个是done,它是一个布尔种的值,当没还多只是回到数据经常回来true。迭代器还会见保留一个中指针,用来对当前集结中值的位置,每调用同样潮next()方法,都见面返回下一个可用之价值

  如果当末一个价值返回后再度调用next()方法,那么回的目标被性能done的价值吗true,属性value则带有迭代器最终回的价值,这个返回值未是数据集的同样片,它与函数的归值类似,是函数调用过程遭到最后一次让调用者传递信息的措施,如果没相关数据则返回undefined

  下面用ES5的语法创建一个迭代器

function createIterator(items) {
    var i = 0;
    return {
        next: function() {
            var done = (i >= items.length);
            var value = !done ? items[i++] : undefined;
            return {
                done: done,
                value: value
            };
        }
    };
}
var iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
// 之后的所有调用
console.log(iterator.next()); // "{ value: undefined, done: true }"

  于面这段代码中,createIterator()方法返回的靶子来一个next()方法,每次调用时,items数组的生一个值会作为value返回。当i为3时,done变为true;此时三元表达式会将value的价设置为undefined。最后两涂鸦调用的结果以及ES6迭代器的终极回机制仿佛,当数集吃用一味后会见返回最终的内容

  上面是示例很复杂,而以ES6受,迭代器的修规则为一如既往复杂,但ES6并且还引入了一个生成器对象,它可以为创建迭代器对象的长河易得重复简约

 

C#调用Javascript函数

生成器

  生成器是同样种回到迭代器的函数,通过function关键字后的星号(*)来代表,函数中会就此到新的重要字yield。星号可以紧挨在function关键字,也可以于中间添加一个空格

// 生成器
function *createIterator() {
    yield 1;
    yield 2;
    yield 3;
}
// 生成器能像正规函数那样被调用,但会返回一个迭代器
let iterator = createIterator();
console.log(iterator.next().value); // 1
console.log(iterator.next().value); // 2
console.log(iterator.next().value); // 3

  于此示例中,createlterator()前之星号表明其是一个生成器;yield关键字也是ES6的新特色,可以经它来指定调用迭代器的next()方法时的返回值及返回顺序。生成迭代器后,连续3不行调动用她的next()方法返回3个不等的值,分别是1、2与3。生成器的调用过程及另函数一样,最终回的是创办好的迭代器

  生成器函数最有趣的部分是,每当执行了一长yield语句后函数就会见自行停止实施。举个例子,在面这段代码中,执行完语句yield
1之后,函数便不再实施另外任何言,直到再次调用迭代器的next()方法才见面继续执行yield
2告词。生成器函数的这种中止函数执行的力量有众多好玩的运

  使用yield关键字可以回去外价值或表达式,所以可以通过生成器函数批量地于迭代器添加元素。例如,可以以循环中使用yield关键字

function *createIterator(items) {
    for (let i = 0; i < items.length; i++) {
        yield items[i];
    }
}
let iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
// 之后的所有调用
console.log(iterator.next()); // "{ value: undefined, done: true }"

  于此示例中,给生成器函数createlterator()传入一个items数组,而以函数内部,for循环不断从数组中生成新的素放入迭代器中,每遇一个yield语句循环都见面停下;每次调用迭代器的next()方法,循环会继续运行并实行下一条yield告句

  生成器函数是ES6被之一个要害特色,可以用其用于所有支持函数使用的地方

【使用范围】

  yield关键字就可每当生成器内部使用,在其它地方以会促成程序抛来左

function *createIterator(items) {
    items.forEach(function(item) {
        // 语法错误
        yield item + 1;
    });
}

  从字面上看,yield关键字确实于createlterator()函数内部,但是它和return关键字一样,二者都未能够过透函数边界。嵌套函数中的return语句不可知看做外部函数的回语句,而此嵌套函数中之yield语句会招致程序抛来语法错误

【生成器函数表达式】

  也得透过函数表达式来创造生成器,只待于function关键字与小括号中添加一个星号(*)即可

let createIterator = function *(items) {
    for (let i = 0; i < items.length; i++) {
        yield items[i];
    }
};
let iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
// 之后的所有调用
console.log(iterator.next()); // "{ value: undefined, done: true }"

  于就段代码中,createlterator()是一个生成器函数表达式,而不是一个函数声明。由于函数表达式是匿名的,因此星号直接在function关键字和小括如泣如诉之间。此外,这个示例基本与前例相同,使用的吧是for循环

  [注意]切莫能够为此箭头函数来创造生成器

【生成器对象的法门】

  由于生成器本身便是函数,因而可用她增长到目标被。例如,在ES5风格的目标字面量中,可以透过函数表达式来创造生成器

var o = {
    createIterator: function *(items) {
            for (let i = 0; i < items.length; i++) {
                yield items[i];
            }
        }
};
let iterator = o.createIterator([1, 2, 3]);

  也可据此ES6的函数方法的简写方式来创造生成器,只待以部数称前上加一个星号(*)

var o = {
    *createIterator(items) {
            for (let i = 0; i < items.length; i++) {
                yield items[i];
            }
        }
};
let iterator = o.createIterator([1, 2, 3]);

  这些示例使用了不同为前的语法,但它的职能实在是齐价格的。在简写版本中,由于无下function关键字来定义createlterator()方法,因此尽管可以以星号和方法名之间留白,但要拿星号紧贴于术名前

【状态机】

  生成器的一个常用功能是生成状态机

let state = function*(){
    while(1){
        yield 'A';
        yield 'B';
        yield 'C';
    }
}

let status = state();
console.log(status.next().value);//'A'
console.log(status.next().value);//'B'
console.log(status.next().value);//'C'
console.log(status.next().value);//'A'
console.log(status.next().value);//'B'

 

非欲取返回值的状态

若页面中若下Javascript的函数sayHello,它的来意是当DOM中创造一个蕴含有“Hello
NanUI!”字样的p元素。

function sayHello() {
    var p = document.createElement("p");
    p.innerText = "Hello NanUI!";

    var container = document.getElementById("hello-container");
    container.appendChild(p);
}

演示中,该函数并从未在Javascript环境里调用,而是在页面加载成功后使NanUI的ExecuteJavascript办法来调动用它。ExecuteJavascript术执行的归来结果吧一个bool类型,它指示了这次有没有发生成实践。

以窗体的构造函数中,通过注册Formium的LoadHandler中的OnLoadEnd事件来监测页面加载成功的景象,并于页面加载成功后调用JS环境被的函数sayHello。

namespace CommunicateBetweenJsAndCSharp
{
    using NetDimension.NanUI;
    public partial class Form1 : Formium
    {
        public Form1()
            : base("http://res.app.local/www/index.html",false)
        {
            InitializeComponent();

            LoadHandler.OnLoadEnd += LoadHandler_OnLoadEnd;
        }

        private void LoadHandler_OnLoadEnd(object sender, Chromium.Event.CfxOnLoadEndEventArgs e)
        {
            // Check if it is the main frame when page has loaded.
            if(e.Frame.IsMain)
            {
                ExecuteJavascript("sayHello()");
            }
        }
    }
}

运行后,可以见到界面被显示了“Hello
NanUI!”字样,说明使用ExecuteJavascript能够调用JS函数。


不过迭代对象

  可迭代对象有Symbol.iterator属性,是平等种及迭代器密切相关的对象。Symbol.iterator通过点名的函数可以返回一个意图被附属对象的迭代器。在ES6负,所有的成团对象(数组、Set集合及Map集合)和字符串都是可迭代对象,这些目标被还有默认的迭代器。ES6遭受初加入的特性for-of循环需要因此到但是迭代对象的这些效应

  [注意]由生成器默认会为Symbol.iterator属性赋值,因此有着通过生成器创建的迭代器都是不过迭代对象

  同开始,我们都提到了巡回里索引跟踪的系题材,要化解这题目,需要少个器:一个凡迭代器,另一个凡是for-of循环。如此一来,便不需要重新跟整个集合的目,只需要关注集合中设拍卖的始末

  for-of循环每执行同一次等还见面调用可迭代对象的next()方法,并拿迭代器返回的结果对象的value属性存储于一个变量中,循环将不断实施这同一进程直到回到对象的done属性的值也true。这里发生个示范

let values = [1, 2, 3];
for (let num of values) {
    //1
    //2
    //3
    console.log(num);
}

  这段for-of循环的代码通过调用values数组的Symbol.iterator方法来获取迭代器,这等同历程是在JS引擎背后完成的。随后迭代器的next()方法被一再调用,从其回来对象的value属性读取值并蕴藏于变量num中,依次为1、2暨3,当结果对象的done属性值为true时巡回退出,所以num不会被赋值为undefined

  如果光需要迭代数组或集合中的值,用for-of循环代替for循环是个对的取舍。相比传统的for循环,for-of循环的主宰标准还简约,不欲追踪复杂的基准,所以还少出错

  [注意]假如以for-of语句用于不可迭代对象、null或undefined将会晤造成程序抛来左

【访问默认迭代器】

  可以由此Symbol.iterator来访问对象默认的迭代器

let values = [1, 2, 3];
let iterator = values[Symbol.iterator]();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"

  于当时段代码中,通过Symbol.iterator获取了数组values的默认迭代器,并因而它遍历数组中之要素。在JS引擎中实行for-of循环语句时为会见出近似之处理过程

  由于负有Symbol.iterator属性的目标都发默认的迭代器,因此可以用她来检测对象是否也可迭代对象

function isIterable(object) {
    return typeof object[Symbol.iterator] === "function";
}
console.log(isIterable([1, 2, 3])); // true
console.log(isIterable("Hello")); // true
console.log(isIterable(new Map())); // true
console.log(isIterable(new Set())); // true
console.log(isIterable(new WeakMap())); // false
console.log(isIterable(new WeakSet())); // false

  这里的islterable()函数可以检查指定对象吃是否存在默认的函数类型迭代器,而for-of循环在实行前也会开一般之自我批评

  除了用内建的可迭代对象类型的Symbol.iterator,也可动用Symbol.iterator来创造属于自己的迭代器

【创建而迭代对象】

  默认情况下,开发者定义之目标还是不足迭代对象,但万一被Symbol.iterator属性添加一个生成器,则足以用其化可迭代对象

let collection = {
    items: [],
    *[Symbol.iterator]() {
        for (let item of this.items) {
            yield item;
        }
    }
};
collection.items.push(1);
collection.items.push(2);
collection.items.push(3);
for (let x of collection) {
    //1
    //2
    //3
    console.log(x);
}

  以此示例中,先创造一个生成器(注意,星号仍然当性能名前)并将那个赋值给目标的Symbol.iterator属性来创造默认的迭代器;而在生成器中,通过for-of循环迭代this.items并因而yield返回各国一个值。collection对象默认迭代器的回值由迭代器this.items自动生成,而非手动遍历来定义返回值

【展开运算符和非数组可迭代对象】

  通过开展运算符(…)可以把Set集合转换成一个数组

let set = new Set([1, 2, 3, 3, 3, 4, 5]),
array = [...set];
console.log(array); // [1,2,3,4,5]

  这段代码中的进行运算符把Set集合的持有值填充到了一个频组字面量里,它可操作有可迭代对象,并因默认迭代器来挑选要引用的价,从迭代器读取所有值。然后按返回顺序以它依次插入到数组中。Set集合是一个只是迭代对象,展开运算符也足以用来其它可迭代对象

let map = new Map([ ["name", "huochai"], ["age", 25]]),
array = [...map];
console.log(array); // [ ["name", "huochai"], ["age", 25]]

  进行运算符把Map集合转换成为包含多个数组的再三组,Map集合的默认迭代器返回的凡大半组键值对,所以结果数组与实践new
Map()时传出的数组看起一样

  以勤组字面量中得以频繁运进行运算符,将只是迭代对象吃之多单元素依次插入新数组中,替换原先展开运算符所在的位置

let smallNumbers = [1, 2, 3],
bigNumbers = [100, 101, 102],
allNumbers = [0, ...smallNumbers, ...bigNumbers];
console.log(allNumbers.length); // 7
console.log(allNumbers); // [0, 1, 2, 3, 100, 101, 102]

  创建一个变量allNumbers,用展开运算符将smallNumbers和bigNumbers里之价依次添加到allNumbers中。首先存入0,然后存入small中的价值,最后存入bigNumbers中的值。当然,原始数组中之价只有是让复制到allNumbers中,它们自身没有改观

  由于开展运算符可以作用被自由而迭代对象,因此要想用只是迭代对象转换为数组,这是无比简便易行的道。既好以字符串中之各个一个字符(不是编码单元)存入新数组中,也堪将浏览器被NodeList对象被之各一个节点存入新的数组中

 

用得到返回值的景

上面的例证中通过ExecuteJavascript计来成功调用了JS环境受到的函数。但容易发现,这种调用方式C#大凡绝非接过至其他返回值的。但其实的种里,我们是得从JS环境得到到返回值的,这时候使用ExecuteJavascript将不可知满足需求,使用另外一个方式EvaluateJavascript可以助我们打JS环境中赢得JS函数的回到值。

倘有另外一个Javascript函数sayHelloToSomeone,它会接一个字符传参数,在部数体中拼接并赶回拼接后底字符串。

function sayHelloToSomeone(who) {
    return "Hello " + who + "!";
}

一律的,在上头例子LoadHandler的OnLoadEnd事件被我们来推行sayHelloToSomeone,并通过C#传递参数并得到拼接后的返值。EvaluateJavascript措施通过一个回调Action来取JS环境面临之回到值。这个Action有零星独参数,第一个凡是返回值的会师,第二只凡是JS环境之生对象,如果函数正确履行,那么第二个参数为null

namespace CommunicateBetweenJsAndCSharp
{
    using NetDimension.NanUI;
    public partial class Form1 : Formium
    {
        public Form1()
            : base("http://res.app.local/www/index.html",false)
        {
            InitializeComponent();

            LoadHandler.OnLoadEnd += LoadHandler_OnLoadEnd;
        }

        private void LoadHandler_OnLoadEnd(object sender, Chromium.Event.CfxOnLoadEndEventArgs e)
        {
            // Check if it is the main frame when page has loaded.
            if(e.Frame.IsMain)
            {
                EvaluateJavascript("sayHelloToSomeone('C#')", (value, exception) =>
                {
                    if(value.IsString)
                    {
                        // Get value from Javascript.
                        var jsValue = value.StringValue;

                        MessageBox.Show(jsValue);
                    }
                });
            }
        }
    }
}

以地方的言传身教中,通过我们得以一目了然知道JS函数sayHelloToSomeone的返回值一定为String类型,因此在C#的回调中一直运用Value的StringValue属性来抱JS函数的字符传返回值。但于实际的施用被,有或连无净知道返回值的色,因此要用Value中放到的逐条判断属性来挨家挨户筛选返回值。

急需小心的是,Value的切近是是ChromiumFX中的CfrV8Value项目,它是一个怪重要的项目,基本上有在C#同CEF间的通信都是由于这路来好的。


内建迭代器

  迭代器是ES6的一个最主要组成部分,在ES6面临,已经默认为许多舅修类提供了内建迭代器,只有当这些内建迭代器无法实现目标时才用团结创造。通常来说当定义自己之对象和类时才会碰到这种情景,否则,完全好凭内建的迭代器完成工作,而最常使用的也许是集聚的那些迭代器

【集合对象迭代器】

  以ES6受发生3种植类型的聚合对象:数组、Map集合与Set集合

  为了重新好地走访对象被之始末,这3栽对象都内打了以下三种植迭代器

entries() 返回一个迭代器,其值为多个键值对
values() 返回一个迭代器,其值为集合的值
keys() 返回一个迭代器,其值为集合中的所有键名

  调用以上3个点子还好拜集合的迭代器

entries()迭代器

  每次调用next()方法时,entries()迭代器都见面回去一个数组,数组中之星星单因素分别代表集合中每个元素的键和价值。如果让遍历的对象是数组,则第一独因素是数字型的目录;如果是Set集合,则第一个因素和亚只要素还是价值(Set集合中的值为同时作为键和价值使用);如果是Map集合,则率先个元素也键名

let colors = [ "red", "green", "blue" ];
let tracking = new Set([1234, 5678, 9012]);
let data = new Map();
data.set("title", "Understanding ES6");
data.set("format", "ebook");
for (let entry of colors.entries()) {
    console.log(entry);
}
for (let entry of tracking.entries()) {
    console.log(entry);
}
for (let entry of data.entries()) {
    console.log(entry);
}

  调用console.log()方法后输出以下内容

[0, "red"]
[1, "green"]
[2, "blue"]
[1234, 1234]
[5678, 5678]
[9012, 9012]
["title", "Understanding ES6"]
["format", "ebook"]

  于即时段代码中,调用每个集合的entries()方法赢得一个迭代器,并以for-of循环来任何历元素,且经过console将各国一个靶的键值对出口出来

values()迭代器

  调用values()迭代器时会见回来集合中所抱的所有值

let colors = [ "red", "green", "blue" ];
let tracking = new Set([1234, 5678, 9012]);
let data = new Map();
data.set("title", "Understanding ES6");
data.set("format", "ebook");
for (let value of colors.values()) {
    console.log(value);
}
for (let value of tracking.values()) {
    console.log(value);
}
for (let value of data.values()) {
    console.log(value);
}

  调用console.log()方法后输出以下内容

"red"
"green"
"blue"
1234
5678
9012
"Understanding ES6"
"ebook"

  如达到所示,调用values()迭代器后,返回的凡每个集合中蕴藏的审数据,而未含有数据以集聚中的位置信息

keys()迭代器

  keys()迭代器会回到集合中设有的各个一个键。如果遍历的凡频繁组,则会回来数字型的键,数组本身的任何属性不会见受归;如果是Set集合,由于键和价值是千篇一律的,因此keys()和values()返回的吗是同的迭代器;如果是Map集合,则keys()迭代器会回每个独立的键

let colors = [ "red", "green", "blue" ];
let tracking = new Set([1234, 5678, 9012]);
let data = new Map();
data.set("title", "Understanding ES6");
data.set("format", "ebook");
for (let key of colors.keys()) {
    console.log(key);
}
for (let key of tracking.keys()) {
    console.log(key);
}
for (let key of data.keys()) {
    console.log(key);
}

  调用console.log()方法后输出以下内容

0
1
2
1234
5678
9012
"title"
"format"

  keys()迭代器会赢得colors、tracking和data这3独集聚中之各一个键,而且各自于3独for-of循环之中以这些键名打印出来。对于数组对象的话,无论是否为数组添加命名属性,打印出的都是数字型的目;而for-in循环迭代之凡频繁组属性而不是数字型的目

差集合类型的默认迭代器

  每个集合类型且发出一个默认的迭代器,在for-of循环中,如果没显式指定则采用默认的迭代器。数组和Set集合的默认迭代器是values()方法,Map集合的默认迭代器是entries()方法。有矣这些默认的迭代器,可以再自在地在for-of循环中行使集合对象

let colors = [ "red", "green", "blue" ];
let tracking = new Set([1234, 5678, 9012]);
let data = new Map();
data.set("title", "Understanding ES6");
data.set("format", "print");
// 与使用 colors.values() 相同
for (let value of colors) {
    console.log(value);
}
// 与使用 tracking.values() 相同
for (let num of tracking) {
    console.log(num);
}
// 与使用 data.entries() 相同
for (let entry of data) {
    console.log(entry);
}

  上述代码未指定迭代器,所以用采取默认的迭代器。数组、Set集合及Map集合的默认迭代器也会见影响产生这些目标的初始化过程,所以马上段代码会输出以下内容

"red"
"green"
"blue"
1234
5678
9012
["title", "Understanding ES6"]
["format", "print"]

  默认情况下,如果是数组和Set集合,会相继返回集合中具备的值。如果是Map集合,则随Map构造函数参数的格式返回相同的数组内容。而WeakSet集合与WeakMap集合就不曾内建的迭代器,由于要管理弱引用,因而无法适用地领略集合中设有的价值,也就无法迭代这些聚集了

【字符串迭代器】

  自ES5宣布之后,JS字符串慢慢转移得再如数组了,例如,ES5正经确定好经方括号访问字符串中的字符(也就是说,text[0]足抱字符串text的率先单字符,并盖此类推)。由于方括号操作的是编码单元而非字符,因此无法对访问对许节约字符

var message = "A 𠮷 B" ;
for (let i=0; i < message.length; i++) {
    console.log(message[i]);
}

  于及时段代码中,访问message的length属性获取索引值,并透过方括号访问来迭代并打印一个词符字符串,但是出口的结果却与预期不符

A




B

  由于双字节字符被看成两单独立的编码单元,从而最终以A与B之间打印出4独空行

  所幸,ES6的靶子是包罗万象支持Unicode,并且我们可由此反字符串的默认迭代器来化解此问题,使该操作字符而不是编码单元。现在,修改前一个示范中字符串的默认迭代器,让for-of循环输出正确的情节

var message = "A 𠮷 B" ;
for (let c of message) {
    console.log(c);
}

  这段代码输出以下内容

A

𠮷

B

  这个结果再合乎预期,通过循环语句可以一直操作字符并成功打印出Unicode字符

【NodeList迭代器】

  DOM标准中生一个NodeList类型,document对象吃之富有因素还为此者路来表示。对于编写Web浏览器环境被之JS开发者来说,需要花费鲜功夫去领略NodeList对象及数组之间的异样。二者都下length属性来代表集合中元素的数额,都得以通过方括号来访问集合中之独立元素。而在中贯彻着,二者的显现异常不等同,因而会促成广大困扰

  自从ES6补充加了默认迭代器后,DOM定义着的NodeList类型(定义在HTML标准要非是ES6正经被)也享有了默认迭代器,其表现跟高频组的默认迭代器完全一致。所以可以将NodeList应用为for-of循环和外支持对象默认迭代器的地方

var divs = document.getElementsByTagName("div");
for (let div of divs) {
    console.log(div.id);
}

  于当时段代码中,通过调用getElementsByTagName()方法赢得到document对象吃所有div元素的列表,在for-of循环中遍历列表中之诸一个素并出口元素ID,实际上是遵循拍卖数组的方式来处理NodeList的

 

Javascript调用C#目标与方式

高等迭代器

  迭代器的根基力量可帮完成很多任务,通过生成器创建迭代器的经过为老省心,除了这些简单的集结遍历任务外,迭代器也得吃用来完成有苛的职责

【给迭代器传递参数】

  迭代器既好用迭代器的next()方法返回值,也得以在生成器内部采用yield关键字来生成值。如果给迭代器的next()方法传递参数,则这参数的价就是会见取代生成器内部及条yield语句之返值。而如果要促成再多像异步编程这样的高档功能,那么这种给迭代器传值的力量就是变得要

function *createIterator() {
    let first = yield 1;
    let second = yield first + 2; // 4 + 2
    yield second + 3; // 5 + 3
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next(4)); // "{ value: 6, done: false }"
console.log(iterator.next(5)); // "{ value: 8, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"

  第一不良调用next()方法时无传入什么参数都见面受废弃。由于传为next()方法的参数会代表上一次yield的归值,而以第一软调用next()方法前未见面实施任何yield语句,因此于第一潮调用next()方法时传递参数是毫无意义的

  第二次调用next()方法传入数值4看作参数,它最终为赋值给生成器函数内部的变量first。在一个含参yield语句被,表达式右侧等价于第一蹩脚调用next()方法后的产一个回来值,表达式左侧等价于次坏调用next()方法后,在函数继续执行前赢得的回值。第二糟调用next()方法传入的值也4,它见面给赋值给变量first,函数则继续执行。第二条yield语句以首先次等yield的结果上加了2,最终的返回值为6

  第三破调用next()方法时,传入数值5,这个价为赋值给second,最后用于第三漫漫yield语句并最终回数值8

【在迭代器中丢掉来荒谬】  

  除了叫迭代器传递数据外,还足以为其传递错误条件。通过throw()方法,当迭代器恢复执行时只是叫其遗弃来一个错误。这种主动弃来错误的能力对异步编程而言重要性,也能够提供模拟了函数执行之星星种植方法(返回值或抛出错误),从而增强生成器内部的编程弹性。将错误对象传为throw()方法后,在迭代器继续执行时那见面给抛弃来

function *createIterator() {
    let first = yield 1;
    let second = yield first + 2; // yield 4 + 2 ,然后抛出错误
    yield second + 3; // 永不会被执行
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next(4)); // "{ value: 6, done: false }"
console.log(iterator.throw(new Error("Boom"))); // 从生成器中抛出了错误

  以这示例中,前少独表达式正常求值,而调用throw()方法后,在继续执行let
second求值前,错误就是会见于扔来并截留了代码继续执行。这个过程与一直扔来荒谬非常相似,二者唯一的分别是废弃来的火候不比

  可以当生成器内部通过try-catch代码片来捕获这些错

function *createIterator() {
    let first = yield 1;
    let second;
    try {
        second = yield first + 2; // yield 4 + 2 ,然后抛出错误
    } catch (ex) {
        second = 6; // 当出错时,给变量另外赋值
    }
    yield second + 3;
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next(4)); // "{ value: 6, done: false }"
console.log(iterator.throw(new Error("Boom"))); // "{ value: 9, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"

  在此示例中,try-catch代码片包裹着第二长达yield语句。尽管就条告句子我没有错,但在被变量second赋值前还是碰头再接再厉弃来荒谬,catch代码片捕获错误后拿second变量赋值为6,下一条yield报告句继续执行后回去回9

  这里发出一个诙谐之情景调用throw()方法后呢会见像调用next()方法同样返回一个结实对象。由于当生成器内部捕获了这荒唐,因而会继续执行下一条yield语句,最终回到数值9

  如此一来,next()和throw()就像是迭代器的星星点点条指令,调用next()方法命令迭代器继续执行(可能提供一个值),调用throw()方法也会见命迭代器继续执行,但又为废弃来一个荒唐,在此之后的施行进程在生成器内部的代码

  于迭代器内部,如果以了yield语句,则可通过next()方法和throw()方法控制实施过程,当然,也得运用return语句返回一些与平常函数返回语句不顶相同的情节

【生成器返回语句】

  由于生成器也是函数,因此得以透过return语词提前退出函数执行,对于最后一不成next()方法调用,可以积极为那个指定一个赶回值。正而在其它函数中那样,可以经过return语句指定一个归值。而当生成器中,return代表拥有操作就完结,属性done被设置也true;如果同时提供了对应的价,则属性value会被装为这个价

function *createIterator() {
    yield 1;
    return;
    yield 2;
    yield 3;
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"

  这段代码中之生成器包含多漫长yield语句和同一修return语句,其中return语词紧按第一长达yield语句,其后的yield语句以未见面被实践

  于return语句被吗得指定一个赶回值,该值将给赋值给返回对象的value属性

function *createIterator() {
    yield 1;
    return 42;
}
let iterator = createIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 42, done: true }"
console.log(iterator.next()); // "{ value: undefined, done: true }"

  以此示例中,第二次等调用next()方法时返回对象的value属性值为42,done属性首次而为true;第三浅调用next()方法还返回一个靶,只是value属性的值会变为undefined。因此,通过return语句指定的归来值,只会于回去对象吃出现平涂鸦,在继续调用返回的目标被,value属性会被重置为undefined

  [注意]进行运算符与for-of循环语词会一直忽略通过return语句指定的任何返回值,只要done一变为true就及时停止读博其他的值。不管怎样,迭代器的返回值依然是一个那个实惠之特点

【委托生成器】

  于某些情况下,我们要用点滴独迭代器合二也平,这时可以创造一个生成器,再让yield语句添加一个星号,就得拿转移数据的过程委托为其它生成器。当定义这些生成器时,只需要将星号放置在主要字yield和生成器的函数曰中即可

function *createNumberIterator() {
    yield 1;
    yield 2;
}
function *createColorIterator() {
    yield "red";
    yield "green";
}
function *createCombinedIterator() {
    yield *createNumberIterator();
    yield *createColorIterator();
    yield true;
}
var iterator = createCombinedIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: "red", done: false }"
console.log(iterator.next()); // "{ value: "green", done: false }"
console.log(iterator.next()); // "{ value: true, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"

  这里的生成器createCombinedIterator()先后委托了另外两独生成器createNumberlterator()和createColorlterator()。仅因迭代器的回来值来拘禁,它就如是一个一体化的迭代器,可以生成有的值。每一样次等调用next()方法就见面委托相应的迭代器生成对应的价值,直到最后由于createNumberlterator()和cpeateColorlterator()创建的迭代器无法回到重新多之价值,此时实践最后一修yield语句并回到true

  有了生成器委托这个新力量,可以更进一步利用生成器的归值来拍卖千头万绪任务

function *createNumberIterator() {
    yield 1;
    yield 2;
    return 3;
}
function *createRepeatingIterator(count) {
    for (let i=0; i < count; i++) {
        yield "repeat";
    }
}
function *createCombinedIterator() {
    let result = yield *createNumberIterator();
    yield *createRepeatingIterator(result);
}
var iterator = createCombinedIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: "repeat", done: false }"
console.log(iterator.next()); // "{ value: "repeat", done: false }"
console.log(iterator.next()); // "{ value: "repeat", done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"

  于生成器createCombinedlterator()中,执行进程先为信托为了生成器createNumberlterator(),返回值会被赋值给变量result,执行到return
3时会回数值3。这个价就于传到createRepeatinglterator()作为它们的参数,因而生成字符串”repeat”的yield语句会为执行三不行

  无论通过何种方法调用迭代器next()方法,数值3还非会见给归,它不过存在于生成器createCombinedlterator()的其中。但倘若想出口这个价值,则足以额外补充加同条yield语句

function *createNumberIterator() {
    yield 1;
    yield 2;
    return 3;
}
function *createRepeatingIterator(count) {
    for (let i=0; i < count; i++) {
        yield "repeat";
    }
}
function *createCombinedIterator() {
    let result = yield *createNumberIterator();
    yield result;
    yield *createRepeatingIterator(result);
}
var iterator = createCombinedIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: "repeat", done: false }"
console.log(iterator.next()); // "{ value: "repeat", done: false }"
console.log(iterator.next()); // "{ value: "repeat", done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"

  此处新加上的yield语句显式地出口了生成器createNumberlterator()的回值。

  [注意]yield*也不过直接以叫字符串,例如yield*
“hello”,此时将祭字符串的默认迭代器

 

大概的施用示范

点的章中示范了安用C#来调用Javascript中的函数,那么下的情节将介绍如何使用Javascript来调用C#遭之靶子、属性和各种法子。

在此之前,需要介绍NanUI窗体基类Formium蒙之根本性质GlobalObject,您可管他知道成Javascript环境面临的window对象。如果您得在Javascript环境下使用C#遭遇之各种对象、属性与法,都待拿这些目标、属性、方法注册及GlobalObject里。

下的例子,通过以Form1的构造函数中登记一个称作也my的JS对象,并在my放开一个只念属性name,以及showCSharpMessageBoxgetArrayFromCSharpgetObjectFromCSharp其三个函数。

//register the "my" object
var myObject = GlobalObject.AddObject("my");

//add property "name" to my, you should implemnt the getter/setter of name property by using PropertyGet/PropertySet events.
var nameProp = myObject.AddDynamicProperty("name");
nameProp.PropertyGet += (prop, args) =>
{
    // getter - if js code "my.name" executes, it'll get the string "NanUI". 
    args.Retval = CfrV8Value.CreateString("NanUI");
    args.SetReturnValue(true);
};
nameProp.PropertySet += (prop, args) =>
{
    // setter's value from js context, here we do nothing, so it will store or igrone by your mind.
    var value = args.Value;
    args.SetReturnValue(true);
};


//add a function showCSharpMessageBox
var showMessageBoxFunc = myObject.AddFunction("showCSharpMessageBox");
showMessageBoxFunc.Execute += (func, args) =>
{
    //it will be raised by js code "my.showCSharpMessageBox(`some text`)" executed.
    //get the first string argument in Arguments, it pass by js function.
    var stringArgument = args.Arguments.FirstOrDefault(p => p.IsString);

    if (stringArgument != null)
    {
        MessageBox.Show(this, stringArgument.StringValue, "C# Messagebox", MessageBoxButtons.OK, MessageBoxIcon.Information);


    }
};

//add a function getArrayFromCSharp, this function has an argument, it will combind C# string array with js array and return to js context.
var friends = new string[] { "Mr.JSON", "Mr.Lee", "Mr.BONG" };

var getArrayFromCSFunc = myObject.AddFunction("getArrayFromCSharp");

getArrayFromCSFunc.Execute += (func, args) =>
{
    var jsArray = args.Arguments.FirstOrDefault(p => p.IsArray);



    if (jsArray == null)
    {
        jsArray = CfrV8Value.CreateArray(friends.Length);
        for (int i = 0; i < friends.Length; i++)
        {
            jsArray.SetValue(i, CfrV8Value.CreateString(friends[i]));
        }
    }
    else
    {
        var newArray = CfrV8Value.CreateArray(jsArray.ArrayLength + friends.Length);

        for (int i = 0; i < jsArray.ArrayLength; i++)
        {
            newArray.SetValue(i, jsArray.GetValue(i));
        }

        var jsArrayLength = jsArray.ArrayLength;

        for (int i = 0; i < friends.Length; i++)
        {
            newArray.SetValue(i + jsArrayLength, CfrV8Value.CreateString(friends[i]));
        }


        jsArray = newArray;
    }


    //return the array to js context

    args.SetReturnValue(jsArray);

    //in js context, use code "my.getArrayFromCSharp()" will get an array like ["Mr.JSON", "Mr.Lee", "Mr.BONG"]
};

//add a function getObjectFromCSharp, this function has no arguments, but it will return a Object to js context.
var getObjectFormCSFunc = myObject.AddFunction("getObjectFromCSharp");
getObjectFormCSFunc.Execute += (func, args) =>
{
    //create the CfrV8Value object and the accssor of this Object.
    var jsObjectAccessor = new CfrV8Accessor();
    var jsObject = CfrV8Value.CreateObject(jsObjectAccessor);

    //create a CfrV8Value array
    var jsArray = CfrV8Value.CreateArray(friends.Length);

    for (int i = 0; i < friends.Length; i++)
    {
        jsArray.SetValue(i, CfrV8Value.CreateString(friends[i]));
    }

    jsObject.SetValue("libName", CfrV8Value.CreateString("NanUI"), CfxV8PropertyAttribute.ReadOnly);
    jsObject.SetValue("friends", jsArray, CfxV8PropertyAttribute.DontDelete);


    args.SetReturnValue(jsObject);

    //in js context, use code "my.getObjectFromCSharp()" will get an object like { friends:["Mr.JSON", "Mr.Lee", "Mr.BONG"], libName:"NanUI" }
};

运作项目开辟CEF的DevTools窗口,在Console中输入my,就会看到my靶的详细信息。

执行my.showCSharpMessageBox(“SOME TEXT FROM
JS”)
命令,将调用C#的MessageBox来具体JS函数中提供的“SOME TEXT FROM
JS”字样。

执行my.getArrayFromCSharp()能够从C#备受取到我们坐的字符串数组中的老三只字符串。如果以函数中指定了一个数组作为参数,那么指定的这个数组将跟C#的字符串数组合并。

> my.getArrayFromCSharp()
["Mr.JSON", "Mr.Lee", "Mr.BONG"]

> my.getArrayFromCSharp(["Js_Bison", "Js_Dick"])
["Js_Bison", "Js_Dick", "Mr.JSON", "Mr.Lee", "Mr.BONG"]

执行my.getObjectFromCSharp()能够从C#归来我们拼装的目标,该对象有一个字符型的libName特性,以及一个字符串数组friends

> my.getObjectFromCSharp()
Object {libName: "NanUI", friends: Array(3)}

异步任务执行

  生成器令人兴奋的特点多与异步编程有关,JS中的异步编程有利有弊:简单任务之异步化非常容易;而复杂任务之异步化会带许多管制代码的挑战。由于生成器支持以函数中暂停代码执行,因而可深深开掘异步处理的重复多用法

  执行异步操作的民俗方法一般是调用一个函数并尽相应回调函数

let fs = require("fs");
fs.readFile("config.json", function(err, contents) {
    if (err) {
        throw err;
    }
    doSomethingWith(contents);
    console.log("Done");
});

  调用fs.readFile()方法时讲求传入要读取的公文称和一个回调函数,操作结束后会调用该回调函数并检查是不是有不当,如果无就可拍卖回来的情节。如果如实施的任务非常少,那么这么的办法可很好地就任务;如要需嵌套回调或序列化一多样的异步操作,事情会变得非常复杂。此时,生成器和yield语句就派上用场了

【简单任务执行器】

  由于执行yield语句会暂停当前函数的履行进程并等候下一样不善调用next()方法,因此得以创建一个函数,在函数中调用生成器生成相应的迭代器,从而以并非回调函数的基本功及落实异步调用next()方法

function run(taskDef) {
    // 创建迭代器,让它在别处可用
    let task = taskDef();
    // 启动任务
    let result = task.next();
    // 递归使用函数来保持对 next() 的调用
    function step() {
        // 如果还有更多要做的
        if (!result.done) {
            result = task.next();
            step();
        }
    }
    // 开始处理过程
    step();
}

  函数run()接受一个生成器函数作为参数,这个函数定义了延续要执行之职责,生成一个迭代器并将其储存在变量task中。首赖调用迭代器的next()方法时,返回的结果于储存起来稍后继续采用。step()函数会检查result.done的价值,如果也false则实施迭代器的next()方法,并重复实施step()操作。每次调用next()方法时,返回的新星消息总会覆写变量result。在代码的最终,初始化执行step()函数并初步全的迭代过程,每次通过检查result.done来确定是否有再次多任务要实施

  借助这run()函数,可以像这么实践一个蕴含多久yield语句的生成器

run(function*() {
    console.log(1);
    yield;
    console.log(2);
    yield;
    console.log(3);
});

  这个示例最终会朝决定高出口多次调用next()方法的结果,分别吗数值1、2与3。当然,简单输出迭代次数不足以展示迭代器高级功能的实用的处在,下一致步将以迭代器与调用者之间彼此传值

【向任务执行器传递数据】

  给任务执行器传递数据的最好简便方法是,将价值通过迭代器的next()方法传入作为yield的生成值供下次调用。在即时段代码中,只待将result.value传入next()方法即可

function run(taskDef) {
    // 创建迭代器,让它在别处可用
    let task = taskDef();
    // 启动任务
    let result = task.next();
    // 递归使用函数来保持对 next() 的调用
    function step() {
        // 如果还有更多要做的
        if (!result.done) {
            result = task.next(result.value);
            step();
        }
    }
    // 开始处理过程
    step();
}

  现在result.value作为next()方法的参数为传播,这样虽足以在yield调用内传递数据了

run(function*() {
    let value = yield 1;
    console.log(value); // 1
    value = yield value + 3;
    console.log(value); // 4
});

  此示例会向决定高出口两独数值1同4。其中,数值1获自yield
1语词被扭曲传被变量value的价;而4拿走自给变量value加3后转传为value的价值。现在数据现已会以yield调用内互动传递了,只需要一个很小改变就会支持异步调用

【异步任务执行器】

  之前的示范只是于差不多只yield调用内来回传递静态数据,而等一个异步过程有些不同。任务执行器需要懂得回调函数是什么与哪采取它们。由于yield表达式会将价值返回给任务执行器,所有的函数调用都见面回去一个值,因而在某种程度上即为是一个异步操作,任务履行器会一直待直到操作完

  下面定义一个异步操作

function fetchData() {
    return function(callback) {
        callback(null, "Hi!");
    };
}

  本示例的本意是让任务执行器调用的备函数都回去一个好推行回调过程的函数,此处fetchData()函数的返回值是一个只是接受回调函数作为参数的函数,当调用它时会传出一个字符串”Hi!”作为回调函数的参数并推行。参数callback需要经任务执行器指定,以担保回调函数执行时方可和底层迭代器正确交互。尽管fetchData()是一路函数,但概括加加一个推迟方法即可将那个成异步函数

function fetchData() {
    return function(callback) {
        setTimeout(function() {
            callback(null, "Hi!");
        }, 50);
    };
}

  以这个本的fetchData()函数中,让回调函数延迟了50ms再受调用,所以这种模式于一块同异步状态下还运行良好。只需要保证每个要透过yield关键字调用的函数都照同之相同的模式编写

  理解了函数中异步过程的运转方式,可以用任务执行器稍作改。当result.value是一个函数时,任务执行器会先实施之函数再用结果传到next()方法

function run(taskDef) {
    // 创建迭代器,让它在别处可用
    let task = taskDef();
    // 启动任务
    let result = task.next();
    // 递归使用函数来保持对 next() 的调用
    function step() {
        // 如果还有更多要做的
        if (!result.done) {
            if (typeof result.value === "function") {
                result.value(function(err, data) {
                    if (err) {
                        result = task.throw(err);
                        return;
                    }
                    result = task.next(data);
                    step();
                });
            } else {
                result = task.next(result.value);
                step();
            }
        }
    }
    // 开始处理过程
    step();
}

  通过===操作符检査后,如果result.value是一个函数,会传播一个回调函数作为参数调用它,回调函数遵循Node.js有关实施错误的预定:所有或的一无是处在第一独参数(err)中,结果在第二单参数中。如果传入了err,意味着执行进程被生出了左,这时通过task.throw()正确输出错误对象;如果没错误产生,data被盛传task.next()作为结果储存起来,并继续执行step()。如果result.value不是一个函数,则一直拿该扩散next()方法

  现在,这个新本子的天职执行器已经可以用来所有的异步任务了。在Node.js环境中,如果要是自文本被读取一些多少,需要在fs.readFile()外围创建一个包装器(wrapper),并返一个跟fetchData()类似之函数

let fs = require("fs");
    function readFile(filename) {
        return function(callback) {
            fs.readFile(filename, callback);
        };
}

  readFile()接受一个文本称当参数,返回一个得以尽回调函数的函数。回调函数被直传入fs.readFile()方法,读取完成后会实行其

run(function*() {
    let contents = yield readFile("config.json");
    doSomethingWith(contents);
    console.log("Done");
});

  以当时段代码中从未其它回调变量,异步的readFile()操作却健康尽,除了yield关键字外,其他代码和一起代码完全等同,只不过函数执行之凡异步操作。所以按照千篇一律之接口,可以编写一些诵读起来像是联合代码的异步逻辑

  当然,这些示例中应用的模式为有弱点,也便是不可知百分百审认函数吃归的任何函数一定是异步的。着眼当下,最重大之凡会懂得任务尽过程背后的理论知识

 

掉调函数

扭转调函数是Javascript里面要和常用之功能,如果你当JS环境遭受登记之主意有函数型的参数(即回调函数),通过Execute事件之Arguments可以取回调的function,并行使CfrV8Value底ExecuteFunction来施行回调。

//add a function with callback function

var callbackTestFunc = GlobalObject.AddFunction("callbackTest");
callbackTestFunc.Execute += (func,args)=> {
    var callback = args.Arguments.FirstOrDefault(p => p.IsFunction);
    if(callback != null)
    {
        var callbackArgs = CfrV8Value.CreateObject(new CfrV8Accessor());
        callbackArgs.SetValue("success", CfrV8Value.CreateBool(true), CfxV8PropertyAttribute.ReadOnly);
        callbackArgs.SetValue("text", CfrV8Value.CreateString("Message from C#"), CfxV8PropertyAttribute.ReadOnly);

        callback.ExecuteFunction(null, new CfrV8Value[] { callbackArgs });
    }
};

在Console中执行callbackTest(function(result){ console.log(result);
})
将行匿名回调,并得到到C#回传的result对象。

> callbackTest(function(result){ console.log(result); })
Object {success: true, text: "Message from C#"}

每当大部分状况下,在Javascript中回调都是坐执行了有的异步的操作,那么只要这些异步的操作是当C#实践吗是可行的,只是实现起来便比较复杂。下面将演示如何贯彻一个异步回调。

//add a function with async callback
var asyncCallbackTestFunc = GlobalObject.AddFunction("asyncCallbackTest");
asyncCallbackTestFunc.Execute += async (func, args) => {
//save current context
var v8Context = CfrV8Context.GetCurrentContext();
var callback = args.Arguments.FirstOrDefault(p => p.IsFunction);

//simulate async methods.
await Task.Delay(5000);

if (callback != null)
{
    //get render process context
    var rc = callback.CreateRemoteCallContext();

    //enter render process
    rc.Enter();

    //create render task
    var task = new CfrTask();
    task.Execute += (_, taskArgs) =>
    {
        //enter saved context
        v8Context.Enter();

        //create callback argument
        var callbackArgs = CfrV8Value.CreateObject(new CfrV8Accessor());
        callbackArgs.SetValue("success", CfrV8Value.CreateBool(true), CfxV8PropertyAttribute.ReadOnly);
        callbackArgs.SetValue("text", CfrV8Value.CreateString("Message from C#"), CfxV8PropertyAttribute.ReadOnly);

        //execute callback
        callback.ExecuteFunction(null, new CfrV8Value[] { callbackArgs });


        v8Context.Exit();

        //lock task from gc
        lock (task)
        {
            Monitor.PulseAll(task);
        }
    };

    lock (task)
    {
        //post task to render process
        v8Context.TaskRunner.PostTask(task);
    }

    rc.Exit();

    GC.KeepAlive(task);
}

在Console中执行asyncCallbackTest(function(result){
console.log(result);
})
用推行匿名回调,大约5秒后收获到C#回传的result对象。

> asyncCallbackTest(function(result){ console.log(result); })
Object {success: true, text: "Message from C#"}

以上,您曾经略询问了使NanUI如何做到C#和Javascript的互相通信。NanUI基为开源项目ChromiumFX开发,因此C#和Javascript的竞相与ChomiumFX保持一致,如果急需开发尤其错综复杂的意义,请自行检索与参考ChromiumFX的有关API及示范。

以身作则源码

git clone https://github.com/NetDimension/NanUI-Examples-04-Communicate-Between-CSharp-And-JS.git

社群和帮扶

GitHub
https://github.com/NetDimension/NanUI/

交流群QQ群
521854872

帮助作者

倘你爱自之工作,并且期望NanUI持续的上扬,请对NanUI项目进行资助为之来鼓励与支撑自累NanUI的开销工作。你得采取微信或者支付宝来围观下的亚维码进行补助。

相关文章