本节演示代码 Generator 的本质是什么?是否取代了 callback ES7 中引入 async-await const fs = require('fs') const path = require('path') const thunkify = require('thunkify') const co = require('co') const Q = require('q') function fn1() { function* Hello() { yield 100 yield (function () {return 200})() return 300 } var h = Hello() console.log(typeof h) // object console.log(h.next()) // { value: 100, done: false } console.log(h.next()) // { value: 200, done: false } console.log(h.next()) // { value: 300, done: true } console.log(h.next()) // { value: undefined, done: true } } // fn1() function fn2() { const symbolA = Symbol.a const obj = { 'a': 100, 'b': function () {console.log('this is b')}, symbolA: function () {console.log('this is symbol')} } } // fn2() function fn3() { // console.log(Array.prototype.slice) // console.log(Array.prototype[Symbol.iterator]) // let item // for (item of [100, 200, 300]) { // console.log(item) // } const arr = [100, 200, 300] const iterator = arr[Symbol.iterator]() // console.log(iterator.next()) // console.log(iterator.next()) // console.log(iterator.next()) // console.log(iterator.next()) // let i // for (i of iterator) { // console.log(i) // } function* Hello() { yield 100 yield (function () {return 200})() return 300 } const h = Hello() console.log(h[Symbol.iterator]) // [Function: [Symbol.iterator]] // console.log(h.next()) // { value: 100, done: false } // console.log(h.next()) // { value: 200, done: false } // console.log(h.next()) // { value: 300, done: false } // console.log(h.next()) // { value: undefined, done: true } let i for (i of h) { console.log(i) } } // fn3() function fn4() { // function* G() { // const a = yield 100 // console.log('a', a) // const b = yield 200 // console.log('b', b) // const c = yield 300 // console.log('c', c) // } // const g = G() // g.next() // value: 100 // g.next('aaa') // value: 200 // g.next('bbb') // value: 300 // g.next('ccc') // value: undefined // function* fibonacci() { // let [prev, curr] = [0, 1] // for (;;) { // [prev, curr] = [curr, prev + curr] // // 将中间值通过 yield 返回,并且保留函数执行的状态,因此可以非常简单的实现 fibonacci // yield curr // } // } // for (let n of fibonacci()) { // if (n > 1000) { // break // } // console.log(n) // } function* G1() { yield 'a' yield* G2() yield 'b' } function* G2() { yield 'x' yield 'y' } for (let item of G1()) { console.log(item) } } // fn4() function fn5() { // const thunk = function (fileName, codeType) { // // 返回一个只接受 callback 参数的函数 // return function (callback) { // fs.readFile(fileName, codeType, callback) // } // } // const fileName = path.resolve(__dirname, '../data/data1.json') // const readFileThunk = thunk(fileName, 'utf-8') // readFileThunk((err, data) => { // console.log(data.toString()) // }) const thunk = thunkify(fs.readFile) const fileName = path.resolve(__dirname, '../data/data1.json') const readFileThunk = thunk(fileName, 'utf-8') readFileThunk((err, data) => { // 获取文件内容 console.log(data) }) } // fn5() function fn6() { const readFileThunk = thunkify(fs.readFile) const fileName1 = path.resolve(__dirname, '../data/data1.json') const fileName2 = path.resolve(__dirname, '../data/data2.json') const gen = function* () { const r1 = yield readFileThunk(fileName1) console.log(111, r1.toString()) const r2 = yield readFileThunk(fileName2) console.log(222, r2.toString()) } const g = gen() g.next().value((err, data1) => { g.next(data1).value((err, data2) => { g.next(data2) }) }) } // fn6() function fn7() { // 自动流程管理的函数 function run(generator) { const gen = generator() function next(err, data) { const result = gen.next(data) // 返回 { value: [Function], done: ... } if (result.done) { // result.done 表示是否结束 return } result.value(next) // result.value 是一个 thunk 函数 // 思考:如果 yield 后面不是 thunk 函数而是 promise 对象,上一句的 result.value(next) 就可以变为 result.value.then(next) } next() // 手动执行以启动第一次 next } const readFileThunk = thunkify(fs.readFile) const fileName1 = path.resolve(__dirname, '../data/data1.json') const fileName2 = path.resolve(__dirname, '../data/data2.json') const gen = function* () { const r1 = yield readFileThunk(fileName1) console.log(111, r1.toString()) const r2 = yield readFileThunk(fileName2) console.log(222, r2.toString()) } // run(gen) const c = co(gen) c.then(data => { console.log('结束') }) } // fn7() function fn8() { const fileName1 = path.resolve(__dirname, '../data/data1.json') const fileName2 = path.resolve(__dirname, '../data/data2.json') const readFilePromise = Q.denodeify(fs.readFile) const gen = function* () { const r1 = yield readFilePromise(fileName1) console.log(111, r1.toString()) const r2 = yield readFilePromise(fileName2) console.log(222, r2.toString()) } co(gen) } // fn8() function fn9() { let info = '' function* g1() { info += '1' yield* g2() info += '5' } function* g2() { info += '2' yield* g3() info += '4' } function* g3() { info += '3' } var g = g1() g.next() console.log(info) // 12345 } // fn9() function fn10() { class MyKoa extends Object { constructor(props) { super(props); // 存储所有的中间件 this.middlewares = [] } // 注入中间件 use (generator) { this.middlewares.push(generator) } // 执行中间件 listen () { this._run() } _run () { const ctx = this const middlewares = ctx.middlewares co(function* () { let prev = null let i = middlewares.length //从最后一个中间件到第一个中间件的顺序开始遍历 while (i--) { //实际koa的ctx应该指向server的上下文,这里做了简化 //prev 将前面一个中间件传递给当前中间件 prev = middlewares[i].call(ctx, prev); } //执行第一个中间件 yield prev; }) } } // 实验效果 var app = new MyKoa(); app.use(function *(next){ this.body = '1'; yield next; this.body += '5'; console.log(this.body); }); app.use(function *(next){ this.body += '2'; yield next; this.body += '4'; }); app.use(function *(next){ this.body += '3'; }); app.listen(); } fn10() Generator 的本质是什么?是否取代了 callback ES7 中引入 async-await