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

时间:2015-03-10 20:48:56

标签: javascript node.js yield

我正在写一些node.js,通过串口连接与传感器进行交互。用于读取传感器的代码当然是异步的。但是,在我的控制代码中,我需要读取传感器,根据值执行某些操作,再次读取,执行其他操作等。为此,我使用的代码类似于以下自包含测试:< / p>

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()。传感器读取完成后,它会调用回调,然后控制返回主代码。我这样做是因为我可能需要根据之前的读数以不同的顺序读取各种传感器。所以,这是一个值得怀疑的部分:我将this.next.bind(this)作为回调传递给异步读取函数。当启用生成器(--harmony_generators)时,代码似乎有效,但我想知道是否存在我遗漏的陷阱。我对JS来说比较新,所以不要害怕指出明显的:)

2 个答案:

答案 0 :(得分:2)

我还没有深入研究ES6生成器,但是让生成器将自己的.next传递给另一个函数作为回调并不适合我。如果有的话,它可能会造成readSensor失败并且你无法处理失败的情况,最终陷入僵局。

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

这将允许您编写这样的代码(在Node v0.12.0中验证工作):

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()函数的功能,并且可能还有其他的promise库。

答案 1 :(得分:1)

  

所以,这是一个值得怀疑的部分:我将this.next.bind(this)作为回调函数传递给异步读取函数。启用生成器时,代码似乎有效

不,这不起作用。无法像您一样使用new构建生成器。来自the spec

  

如果使用[[Call]]调用生成器,this绑定将以正常方式初始化。如果使用[[Construct]]调用生成器,则this绑定未初始化, FunctionBody 中对this的任何引用都将产生ReferenceError异常

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

  

传感器读数完成后,[...]控制返回主码。

这确实是一个聪明的主意。之前已经进行过探索,请参阅Understanding code flow with yield/generatorsthis article。许多图书馆都支持此especially combined with promises

我建议你使用其中一个库,你当前的代码并不是非常稳定(会破坏完整的ES6支持),而且似乎也缺乏错误处理。