当前位置:K88软件开发文章中心编程语言JavaScriptECMAScript → 文章内容

ECMAScript 6 Generator 函数

减小字体 增大字体 作者:佚名  来源:网上搜集  发布时间:2019-1-15 15:38:37

Promise的语法。Generator函数可以进一步改善代码运行流程。function* longRunningTask(value1) { try { var value2 = yield step1(value1); var value3 = yield step2(value2); var value4 = yield step3(value3); var value5 = yield step4(value4); // Do something with value4 } catch (e) { // Handle any error from step1 through step4 }}然后,使用一个函数,按次序自动执行所有步骤。scheduler(longRunningTask(initialValue));function scheduler(task) { var taskObj = task.next(task.value); // 如果Generator函数未结束,就继续调用 if (!taskObj.done) { task.value = taskObj.value scheduler(task); }}注意,上面这种做法,只适合同步操作,即所有的task都必须是同步的,不能有异步操作。因为这里的代码一得到返回值,就继续往下执行,没有判断异步操作何时完成。如果要控制异步的操作流程,详见后面的《异步操作》一章。下面,利用for...of循环会自动依次执行yield命令的特性,提供一种更一般的控制流管理的方法。let steps = [step1Func, step2Func, step3Func];function *iterateSteps(steps){ for (var i=0; i< steps.length; i++){ var step = steps[i]; yield step(); }}上面代码中,数组steps封装了一个任务的多个步骤,Generator函数iterateSteps则是依次为这些步骤加上yield命令。将任务分解成步骤之后,还可以将项目分解成多个依次执行的任务。let jobs = [job1, job2, job3];function *iterateJobs(jobs){ for (var i=0; i< jobs.length; i++){ var job = jobs[i]; yield *iterateSteps(job.steps); }}上面代码中,数组jobs封装了一个项目的多个任务,Generator函数iterateJobs则是依次为这些任务加上yield *命令。最后,就可以用for...of循环一次性依次执行所有任务的所有步骤。for (var step of iterateJobs(jobs)){ console.log(step.id);}再次提醒,上面的做法只能用于所有步骤都是同步操作的情况,不能有异步操作的步骤。如果想要依次执行异步的步骤,必须使用后面的《异步操作》一章介绍的方法。for...of的本质是一个while循环,所以上面的代码实质上执行的是下面的逻辑。var it = iterateJobs(jobs);var res = it.next();while (!res.done){ var result = res.value; // ... res = it.next();}(3)部署Iterator接口利用Generator函数,可以在任意对象上部署Iterator接口。function* iterEntries(obj) { let keys = Object.keys(obj); for (let i=0; i < keys.length; i++) { let key = keys[i]; yield [key, obj[key]]; }}let myObj = { foo: 3, bar: 7 };for (let [key, value] of iterEntries(myObj)) { console.log(key, value);}// foo 3// bar 7上述代码中,myObj是一个普通对象,通过iterEntries函数,就有了Iterator接口。也就是说,可以在任意对象上部署next方法。下面是一个对数组部署Iterator接口的例子,尽管数组原生具有这个接口。function* makeSimpleGenerator(array){ var nextIndex = 0; while(nextIndex < array.length){ yield array[nextIndex++]; }}var gen = makeSimpleGenerator(['yo', 'ya']);gen.next().value // 'yo'gen.next().value // 'ya'gen.next().done // true(4)作为数据结构Generator可以看作是数据结构,更确切地说,可以看作是一个数组结构,因为Generator函数可以返回一系列的值,这意味着它可以对任意表达式,提供类似数组的接口。function *doStuff() { yield fs.readFile.bind(null, 'hello.txt'); yield fs.readFile.bind(null, 'world.txt'); yield fs.readFile.bind(null, 'and-such.txt');}上面代码就是依次返回三个函数,但是由于使用了Generator函数,导致可以像处理数组那样,处理这三个返回的函数。for (task of doStuff()) { // task是一个函数,可以像回调函数那样使用它}实际上,如果用ES5表达,完全可以用数组模拟Generator的这种用法。function doStuff() { return [ fs.readFile.bind(null, 'hello.txt'), fs.readFile.bind(null, 'world.txt'), fs.readFile.bind(null, 'and-such.txt') ];}上面的函数,可以用一模一样的for...of循环处理!两相一比较,就不难看出Generator使得数据或者操作,具备了类似数组的接口。

上一页  [1] [2] [3] [4] [5] [6] [7] 


ECMAScript 6 Generator 函数