NodeJS: 使用 (Generator) 生成器解决 JavaScript 回调嵌套问题
来源:互联网 发布:python url编码 编辑:程序博客网 时间:2024/06/08 15:57
转自:http://huangj.in/765
回调地狱 (http://callbackhell.com/) 作为 JavaScript 开发的门槛,一直让小白心力交瘁,也一直让大神以此鄙视小白。
为了解决这个问题,Async、事件触发机制、Promise/A 各种工作流的控制方案被提出并应用于各种场景下。
本文所介绍的 Generator 是 EcmaScript Harmony (ES6) 引入的新特性,并且通过该特性,我们能够很好地改变代码结构,以更可读的代码解决工作流中的回调嵌套问题。
实践出真知,本文的内容是基于 Node.js 0.11.9 环境下通过运行测试得出的结论。不保证与 ES6 标准完全一致。
如何创建 Generator
function * foo( input ) { var res = yield input;}
使用上面的代码,我们就声明了一个 Generator 。
Generator 的使用
function * foo( input ) { var res = yield input;}var g = foo(10);g.next(); // { value: 10, done: false }g.next(); // { value: undefined, done: true }
在上面的代码中,我们像使用一般函数一样,通过函数调用的形式得到了一个 Generatorg
Object.prototype.toString.call(g) // [object Generator]
我们可以使用 g.next()
方法使代码执行到下一个 yield
的位置。
如此反复,我们就可以将整个函数执行完。
g.next() 的参数和返回值
首先说返回值。
g.next()
的返回值包含两个属性,value
和 done
。
返回值的 done 属性
使用 done
属性,我们可以来检测生成器函数是否执行完成。例如上面的例子,当函数尚未结束时,done
为假;当函数全部执行结束后,done
为真。
这样在循环执行 next()
时,可以利用这个值的真假来决定是否继续循环。
while(!g.next().done) { // do something;}
返回值的 value 属性
value
属性的值为 yield
关键字右侧表达式的值。
在上面的例子里,就是 input
的值。由于是表达式,我们可以在里面做各种运算。
function * foo( input ) { var res = yield input / 2; // 修改这里的表达式}var g = foo(10);g.next(); // { value: 5, done: false } 5 == input / 2g.next(); // { value: undefined, done: true }
如上,我们修改改 yield 右侧的表达式,此时,调用 g.next()
时,我们得到了表达式运算后的结果。
g.next() 的参数
g.next()
的参数就是 yield
的返回值。举例说明
function * foo( input ) { var res = yield input; console.log('res is ', res);}var g = foo(10);g.next(); // 到达第一个 yield,返回 input 的值g.next(100); // 将 100 作为参数传入// console log// res is 100// 100 作为 yield 的返回值赋值给了 res 变量
用 Generator 改变回调的写法
了解了 Generator 的基本用法,这里就将其应用于具体的业务场景,我们看看他怎么解决回调嵌套的问题。
首先引入一个简单的工具来处理
// 当前的 Generatorvar activeGenerator;// 处理 g.next() 功能function gNext() { return function (err, data) { if (err) { throw err; } // 前文中的 g.next(),并把回调函数的结果作为参数传递给 yield activeGenerator.next(data) }}// 控制工具function gQueue(generatorFunc) { activeGenerator = generatorFunc(gNext()); activeGenerator.next();}
这个工具做的事情很简单,把生成器作为参数传递进去,他会自动地去触发 g.next() 来执行整个工作流。
一段工作流
function asyncFunc(cb) { // 这个函数模拟一个异步操作,将在 1 秒后触发回调函数 setTimeout(function() { cb(null, 100); }, 1000)}// 声明一个 Generator 并传给 gQueuegQueue(function * flow(next) { console.log('start'); // 执行异步函数 asyncFunc,并把 next 注册在其回调函数里 var y = yield asyncFunc(next); // 回调执行完成后,会触发 g.next(),此时 y 的值为 asyncFunc 回调里的 100 console.log('y is', y); // 同上 var z = yield asyncFunc(next); console.log('z is ', z); console.log('end')});// console log// start// y is 100// z is 100// end
看出来这段代码的作用了么。
asyncFunc
是个异步的函数,他会在 1s 之后触发回调。
我们的 gQuery
调用 Generator 的时候,会把一个 next
方法作为参数传入 Generator。
Generator 里异步方法调用时,将 next
注册在成功回调之后执行,此时,该方法会去主动调用 Generator 的 next 方法,并将异步方法回调的结果作为参数传递个 g.next()
。
就这样那样,你自己理解一下。然后代码就走完了。
看起来和 express/connect 的 next 参数差不多,但是仔细看,回调嵌套没有了。
原本需要回调嵌套的地方居然以类似同步代码的形式写出来了。
在 Generator 的帮助下,业务逻辑用同步形式的代码写出来了,并且后端还是以异步无阻塞的方式去执行。
是不是爽翻了!
总结
本文仅仅从功能上测试了使用 Generator 来回避回调地狱的问题,并给出了一种简单的基础方法,目前已经有相关框架( koa )和库( suspend )提供了使用 Generator 机制的控制流。
目前在 Node.js 0.11.9 下,可以在启动时添加 --harmony
参数来开启对 ES Harmony 的支持。
期待 ES Harmony 标准早日确定,也期待 Node.js 0.12 早日发布以把这些特性应用于生产环境中。
- NodeJS: 使用 (Generator) 生成器解决 JavaScript 回调嵌套问题
- 使用JavaScript生成器解决回调问题的研究
- javascript---生成器(generator)
- JavaScript ES7 中使用 async/await 解决回调函数嵌套问题
- JavaScript ES7 中使用 async/await 解决回调函数嵌套问题
- 使用Python生成器解决八皇后问题
- 生成器 generator
- 生成器generator
- 生成器generator
- 生成器generator
- 【rapid-generator】代码生成器工具使用
- mybatis-generator自动生成器插件使用详解
- 使用mybatis-generator代码生成器实例
- Mybatis-generator生成器的使用步骤
- mybatis自动生成器(mybatis.generator)使用
- 关于使用MyBatis-Generator时自定义注解生成器的一些问题
- 密码生成器怎么用 password generator密码生成器使用教程
- try- catch嵌套使用解决的问题
- Android事件分发机制完全解析,带你从源码的角度彻底理解(下)
- Eucalyptus学习汇总
- POJ 3667 Hotel (线段树区间合并 )
- inline elment new line
- SQLServer找出执行慢的SQL语句
- NodeJS: 使用 (Generator) 生成器解决 JavaScript 回调嵌套问题
- ArcGIS for Android 10.1.1API 中文标注导致程序异常崩溃问题
- iOS kvc
- 零时表
- 求一个数的二进制表示中1的个数
- SQL Server将列值转为列名输出
- wordpress优化头部
- 内存池技术介绍
- js undefined & null