使用生成器函数next()作为node.js中的callback函数

我正在写一些node.js通过串口连接与传感器交互。 读取传感器的代码自然是asynchronous的。 然而,在我的控制代码中,我需要读取一个传感器,根据这个值做一些事情,再读一遍,做一些其他的事情等。为此,我使用如下的自包含testing代码:

var main = new Main(); main.next(); function* Main() { var reading = yield readSensor(this.next.bind(this)); console.log(reading); var reading = yield readSensor(this.next.bind(this)); console.log(reading); } function readSensor(callback) { // simulate asynchrounous callback from reading sensor setTimeout(function sensorCallback() { callback('foo'); }, 100); } 

所以,我的顺序控制代码是在一个生成器,当它需要读取时产生readSensor() 。 传感器读数完成后,它会调用callback,控制返回到主代码。 我这样做是因为我可能需要根据以前的读数以不同的顺序读取各种传感器。 所以,这里是有问题的部分:我将this.next.bind(this)作为callback传递给asynchronous读取函数。 代码似乎工作时,生成器启用( --harmony_generators ),但我想知道是否有缺陷在这里,我失踪。 我对JS比较新,所以不要害怕指出明显的:)

我没有深入研究过ES6生成器,但是有一个生成器将自己的.next传递给另一个函数,因为callback函数并不适合我。 如果有的话,它可能会导致readSensor失败,你无法处理失败,最终陷入僵局。

我build议修改或包装readSensor以返回承诺,然后使用本文中概述的技术。

这将允许您编写这样的代码(在Node v0.12.0中进行了validation):

 var Promise = require('q'); var main = async(function* () { var reading = yield readSensor(); console.log(reading); reading = yield readSensor(); console.log(reading); }); main(); function readSensor() { return Promise.delay(2000).thenResolve(Math.random() * 100); } /*********************************************************** * From here down, * * boilerplate async() function from article linked above * ***********************************************************/ function async(makeGenerator){ return function () { var generator = makeGenerator.apply(this, arguments); function handle(result){ // result => { done: [Boolean], value: [Object] } if (result.done) return Promise.resolve(result.value); return Promise.resolve(result.value).then(function (res){ return handle(generator.next(res)); }, function (err){ return handle(generator.throw(err)); }); } try { return handle(generator.next()); } catch (ex) { return Promise.reject(ex); } } } 

正如下面的loganfsmyth所指出的那样,Q已经提供了一个Q.async()方法,它提供了这个async()函数的function,也可能还有其他的promise库。

所以,这里是有问题的部分:我将this.next.bind(this)作为callback传递给asynchronous读取函数。 代码似乎在启用生成器时工作

不,这不行。 发电机不能像你一样使用new构造。 从规格 :

如果使用[[Call]]调用生成器,则this绑定将以正常方式进行初始化。 如果使用[[Construct]]调用生成器,则不会初始化this绑定,并且在 FunctionBody中this任何引用 都将产生ReferenceErrorexception。

使用new调用生成器函数(请参见第9.2.3节 , derived的[[ConstructorKind]]),但它们不构造实例。

当传感器读数完成后,控制返回到主代码。

这确实是一个聪明的想法。 以前已经探索过,请参阅使用yield / generator或本文 了解代码stream 。 许多图书馆都支持这一点, 特别是与承诺相结合 。

我build议你使用这些库中的一个,你当前的代码不是很稳定(将会全面支持ES6),而且似乎缺lesserror handling。