Javascript 在node.js中将生成器函数next()用作回调
我正在编写一些node.js来通过串口连接与传感器交互。读取传感器的代码自然是异步的。但是,在我的控制代码中,我需要读取传感器,根据值执行某些操作,再次读取,执行其他操作,等等。为此,我使用的代码类似于以下自包含测试:Javascript 在node.js中将生成器函数next()用作回调,javascript,node.js,yield,Javascript,Node.js,Yield,我正在编写一些node.js来通过串口连接与传感器交互。读取传感器的代码自然是异步的。但是,在我的控制代码中,我需要读取传感器,根据值执行某些操作,再次读取,执行其他操作,等等。为此,我使用的代码类似于以下自包含测试: var main = new Main(); main.next(); function* Main() { var reading = yield readSensor(this.next.bind(this)); console.log(reading); v
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\u generators
),但我想知道这里是否有我遗漏的陷阱。我对JS比较陌生,所以不要害怕指出显而易见的:)我没有深入研究ES6生成器,但是让一个生成器传递它自己的。下一步作为回调函数传递给另一个函数对我来说并不合适。如果有任何问题,它可能会造成readSensor
出现故障,而您无法处理故障,从而导致死锁
我建议修改或包装readSensor
以返回承诺,然后使用中概述的技术
这将允许您编写如下代码(已验证在节点v0.12.0中工作):
正如下面loganfsmyth所指出的,Q已经提供了一个Q.async()
方法,该方法提供了这个async()
函数的功能,其他promise库可能也提供了这个功能
所以,这里有一个问题:我将this.next.bind(this)
作为异步读取函数的回调传递。当发电机启用时,代码似乎起作用
不,那不行。不能像您那样使用new
构造生成器。发件人:
如果使用[[Call]]调用生成器,则此
绑定将已以正常方式初始化。如果使用[[Construct]]调用生成器,则不会初始化此
绑定,函数体中对此
的任何引用都将产生引用错误
异常
生成器函数可以通过new
调用(请参见[[ConstructorKind]]的derived
),但它们不构造实例
传感器读数完成后,[…]控制返回主代码
这的确是个聪明的主意。之前已对其进行过探索,请参见或。许多库都支持这一点
我建议您使用这些库中的一个,您当前的代码不是很稳定(将在完全支持ES6的情况下中断),而且似乎还缺少错误处理。完全没有主要问题,*
在这种情况下的目的是什么?有一个由内存地址引用的函数吗?我从未在JS中看到过这一点。@Vadorequest它表示一个。谢谢,几个月前我读过关于ES6功能的文章,但我完全忘记了这一点!这是比较新的,谢谢。在研究这个问题时,我简要地看了一下Q.async,但被有关示例的警告吓跑了。当然,我想,在这一点上,同样的警告也适用于任何使用发电机的情况。我可能会采用这种方法。我想,作为一名长期的C++程序员,我对如何使用库来获得相当基本的控制流感到震惊。再一次,从JS转到C(++),我可以想象自己被震惊了,因为我需要处理信号量、互斥量等来防止代码自身崩溃。@tyapo使用类似同步代码的语法在单个线程上运行并行异步操作,这并不是我所说的“非常基本的控制流”。确实,在使用块代码进行这些工作的语言中,为了做一些理所当然的事情,您必须跳过一些障碍,但是最终的结果要好得多。上面完整复制的async()
函数就是生成函数使用这种神奇的async/await语法所需的全部,您应该能够将它与任何承诺库或可能的内置承诺结合起来,一旦它们准备好了。我不认为您可以像构造函数一样调用ES6生成器。也许是v8引擎的错误?让我检查一下。@Bergi我查看了最新的ES6草案规范,但无法决定是否支持该规范。我想应该是,;这将是一种轻量级的、相对干净的方法来处理嵌套回调问题。当然,即使您不能将生成器构造为对象,使其具有一个this
,您也可以使用初始的main.next(main)向它们发送“self”代码>呼叫,以初始收益率接收。但是,就目前而言,Q.async库似乎完成了我所追求的目标。我现在已经详细研究了ES6草案,可以证实我的怀疑。见我的答案:-)
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);
}
}
}