From ad0499d0e4b157dd16b1d6905a634efb5d0e3a41 Mon Sep 17 00:00:00 2001 From: ruanyf Date: Sat, 10 May 2014 14:31:20 +0800 Subject: [PATCH] edit docs/iterator & generator --- docs/generator.md | 31 +++++++++++++++++++++++++++++++ docs/iterator.md | 16 +++++++++++++--- docs/reference.md | 1 + 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/docs/generator.md b/docs/generator.md index bb4e0c6..0c47a8e 100644 --- a/docs/generator.md +++ b/docs/generator.md @@ -60,6 +60,8 @@ Generator函数使用iterator接口,每次调用next方法的返回值,就 Generator函数的本质,其实是提供一种可以暂停执行的函数。yield语句就是暂停标志,next方法遇到yield,就会暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回对象的value属性的值。当下一次调用next方法时,再继续往下执行,直到遇到下一个yield语句。如果没有再遇到新的yield语句,就一直运行到函数结束,将return语句后面的表达式的值,作为value属性的值,如果该函数没有return语句,则value属性的值为undefined。 +由于yield后面的表达式,直到调用next方法时才会执行,因此等于为JavaScript提供了手动的“惰性求值”(Lazy Evaluation)的语法功能。 + yield语句与return语句有点像,都能返回紧跟在语句后面的那个表达式的值。区别在于每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行,而return语句不具备位置记忆的功能。 Generator函数可以不用yield语句,这时就变成了一个单纯的暂缓执行函数。 @@ -125,6 +127,35 @@ loadUI.next() 上面代码表示,第一次调用loadUI函数时,该函数不会执行,仅返回一个遍历器。下一次对该遍历器调用next方法,则会显示Loading界面,并且异步加载数据。再一次使用next方法,则会隐藏Loading界面。可以看到,这种写法的好处是所有Loading界面的逻辑,都被封装在一个函数,按部就班非常清晰。 +总结一下,如果某个操作非常耗时,可以把它拆成N步。 + +```javascript + +function* longRunningTask() { + yield step1(); + yield step2(); + // ... + yield stepN(); +} + +``` + +然后,使用一个函数,按次序自动执行所有步骤。 + +```javascript + +scheduler(longRunningTask()); + +function scheduler(task) { + setTimeout(function () { + if (!task.next().done) { + scheduler(task); + } + }, 0); +} + +``` + 注意,yield语句是同步运行,不是异步运行(否则就失去了取代回调函数的设计目的了)。实际操作中,一般让yield语句返回Promises对象。 ```javascript diff --git a/docs/iterator.md b/docs/iterator.md index 0ca0aea..00029b0 100644 --- a/docs/iterator.md +++ b/docs/iterator.md @@ -4,6 +4,8 @@ 遍历器(Iterator)是一种协议,任何对象只要部署这个协议,就可以完成遍历操作。在ES6中,遍历操作特指for...of循环。 +它的作用主要有两个,一是为遍历对象的属性提供统一的接口,二是为使得对象的属性能够按次序排列。 + ES6的遍历器协议规定,部署了next方法的对象,就具备了遍历器功能。next方法必须返回一个包含value和done两个属性的对象。其中,value属性是当前遍历位置的值,done属性是一个布尔值,表示遍历是否结束。 ```javascript @@ -52,7 +54,9 @@ it.next().value // '2' ``` -一个对象只要具备了next方法,就可以用for...of循环遍历它的值。 +## for...of循环 + +ES6中,一个对象只要部署了next方法,就被视为具有iterator接口,就可以用for...of循环遍历它的值。下面用上一节的idMaker函数生成的it遍历器作为例子。 ```javascript @@ -61,12 +65,18 @@ for (var n of it) { break; console.log(n); } +// 0 +// 1 +// 2 +// 3 +// 4 +// 5 ``` -## for...of循环 +上面代码说明,for...of默认从0开始循环。 -ES6中,任何具备了iterator接口的对象,都可以用for...of循环遍历。数组原生具备iterator接口。 +数组原生具备iterator接口。 ```javascript diff --git a/docs/reference.md b/docs/reference.md index caeb69f..1f2f663 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -33,6 +33,7 @@ - Steven Sanderson, [Experiments with Koa and JavaScript Generators](http://blog.stevensanderson.com/2013/12/21/experiments-with-koa-and-javascript-generators/) - jmar777, [What's the Big Deal with Generators?](http://devsmash.com/blog/whats-the-big-deal-with-generators) - Marc Harter, [Generators in Node.js: Common Misconceptions and Three Good Use Cases](http://strongloop.com/strongblog/how-to-generators-node-js-yield-use-cases/): 讨论Generator函数的作用 +- Axel Rauschmayer, [Iterators and generators in ECMAScript 6](http://www.2ality.com/2013/06/iterators-generators.html): 探讨Iterator和Generator的设计目的 ## Promise对象