Using generator next () function as callback in node.js

I am writing several node.js for interacting with sensors through a serial port. Of course, the code for reading the sensor is asynchronous. However, in my control code I need to read the sensor, do something based on the value, read again, do something else, etc. For this, I use the code as the following standalone test:

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); } 

So, my serial control code is in the generator, which gives readSensor() when it needs to get read. When the sensor is read, it calls a callback and control returns to the main code. I do it this way because I may need to read from different sensors in different orders depending on previous readings. So here is the dubious part: I pass this.next.bind(this) as a callback to the asynchronous read function. The code seems to work when the generators are turned on ( --harmony_generators ), but I'm wondering if there are any flaws here that I miss. I'm relatively new to JS, so don't be afraid to point out the obvious :)

+5
source share
2 answers

I did not examine ES6 generators in depth, but the generator passed its own .next another function, since the callback is not suitable for me. In any case, this can create a situation in which readSensor fails, and you have no way to deal with this failure, ultimately in a dead end.

I suggest changing or wrapping readSensor to return a promise, and then use the technique described in this article .

This will allow you to write such code (verified in 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); } } } 

As a note, loganfsmyth below Q already provides the Q.async() method, which provides the functionality of this async() function, and possibly other promise libraries.

+2
source

So here is the dubious part: I pass this.next.bind(this) as a callback to the asynchronous read function. Code works when generators are on

No, this does not work. Generators cannot be built using new , like you. From specification :

If the generator was called using [[Call]], the this binding was already initialized in the usual way. If the generator was called using [[Construct]], the this binding is not initialized, and any references to this inside the FunctionBody will throw a ReferenceError exception.

Generator functions are called using new (see ยง9.2.3 , with derived for [[ConstructorKind]]), but they do not instantiate.

When the sensor reading is completed, control [...] returns to the main code.

This is a really smart idea. It was discussed earlier; see Understanding Code Flow with Output / Generators or this article . Many libraries support this, especially when combined with promises .

I suggest you use one of these libraries, your current code is not very stable (it will work with full ES6 support), and it also seems to be missing error handling.

+1
source

Source: https://habr.com/ru/post/1215091/


All Articles