NanUI文档 – 如何兑现C#与Javascript的交互通信。详谈ES6受到的迭代器(Iterator)和生成器(Generator)

by admin on 2018年10月5日

NanUI文档目录

面前的讲话

  • NanUI简介
  • 起用NanUI
  • 打包并使内嵌式的HTML/CSS/JS资源
  • 行使网页来设计总体窗口
  • 怎样落实C#和Javascript的相互通信
  • 怎么样处理NanUI中的下载过程 – DonwloadHandler的以(待更新。。。)
  • 什么处理NanUI中的弹窗过程 – LifeSpanHandler的动(待更新。。。)
  • 何以支配Javascript对话框 – JsDialogHandler的下(待更新。。。)
  • 自打定义资源处理程序 (待更新。。。)

故而循环语词迭代数据常常,必须要初始化一个变量来记录每一样蹩脚迭代在数量集合中的位置,而于众编程语言中,已经起通过程序化的点子因此迭代器对象回来迭代过程中聚集的各国一个要素

如何实现C#跟Javascript的互相通信

透过事先的章,相信您曾对NanUI有了开的打听。但顶目前为止,我们用NanUI仅仅只是作为呈现HTML界面的器皿,并未涉及CEF与C#里面数的并行。那么本文将略介绍如何在NanUI中使用C#调用Javascript的函数和如何以Javascript注入C#的对象、属性与法。

迭代器的使用得大幅度地简化数据操作,于是ES6吧为JS中补充加了此迭代器特性。新的数组方法以及新的联谊类型(如Set集合与Map集合)都依赖迭代器的兑现,这个新特性对速之数码处理而言是必需的,在语言的其余特色中呢都发生迭代器的身形:新的for-of循环、展开运算符(…),甚至并异步编程都可以使用迭代器

C#调用Javascript函数

正文将详细介绍ES6面临的迭代器(Iterator)和生成器(Generator)

莫需要取得返回值的状

要是页面中犹如下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函数。


引入

消取返回值的情景

点的例证中经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间的通信都是由于这个类别来成功的。


下是同段子正式的for循环代码,通过变量i来跟colors数组的目录,循环每次执行时,如果i小于数组长度len则加1,并实施下一样潮循环

Javascript调用C#靶及智

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

简单易行的运示范

上面的篇章被示范了怎么用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目标的详细信息。

图片 1

执行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)}

尽管如此循环语句语法简单,但万一拿多独巡回嵌套则用追踪多单变量,代码复杂度会大大加,一不小心便大错特错使用了其余for循环的跟变量,从而导致程序出错。迭代器的产出旨在祛除这种复杂并减少循环中的不当

转头调函数

拨调函数是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

迭代器是同种异常对象,它有着部分特地为迭代进程设计之专有接口,所有的迭代器对象还发一个next()方法,每次调用都回来一个结果对象。结果对象来点儿只属性:一个凡value,表示产一个就要返回的价值;另一个凡是done,它是一个布尔种的价,当没再多而是回到数据经常返回true。迭代器还见面保留一个中指针,用来对当前集合中值的岗位,每调用平等次等next()方法,都见面返回下一个可用之值

社群和扶植

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

交流群QQ群
521854872

助作者

若你欢喜自的办事,并且希望NanUI持续的提高,请对NanUI项目进展资助为之来鼓励和支持自己继续NanUI的开工作。你得用微信或者支付宝来围观下的次维码进行资助。

图片 2

只要当末一个价返回后再也调用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以还引入了一个生成器对象,它可让创建迭代器对象的过程易得更简约

生成器

生成器是如出一辙栽回到迭代器的函数,通过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'

但是迭代对象

然而迭代对象具备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对象被之各一个节点存入新的数组中

内建迭代器

迭代器是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的

高级迭代器

迭代器的基础功能可拉完成很多职责,通过生成器创建迭代器的长河吧杀省心,除了这些简单的汇聚遍历任务外,迭代器也可吃用来完成有苛的职责

【给迭代器传递参数】

迭代器既好用迭代器的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”,此时将动用字符串的默认迭代器

异步任务执行

生成器令人兴奋的性状多跟异步编程有关,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关键字外,其他代码和一同代码完全一致,只不过函数执行之凡异步操作。所以按照平等之接口,可以编制一些念起来如是一道代码的异步逻辑

本来,这些示例中使的模式为发生弱点,也便是免能够百分百着实认函数吃回到的其它函数一定是异步的。着眼当下,最要害之是力所能及知道任务履行过程背后的理论知识

以上就首详谈ES6被之迭代器(Iterator)和生成器(Generator)就是聊编分享给大家之全部内容了,希望能够让大家一个参照,也想大家多支持脚本的小。

你或许感兴趣的文章:

  • ES6初特点三:
    Generator(生成器)函数详解
  • ES6饱受Generator与异步操作实例分析
  • JavaScript中 ES6
    generator数据类型详解
  • 详解JavaScript
    ES6中的Generator
  • Es6 Generator函数详细剖析

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图