0

I am trying to create a Node module (using harmony) that upon loading by another module/application, has to be yielded to so that things in it's construct can be executed and loaded before any of it's exposed functions can be called.

The issue I am having is that I cannot seem to yield to the internal function that is being executed, using module.exports. An example would help.

module.exports = function*(s_id){
    console.log('loading the module lets it execute up till here');
    if (!(this instanceof Tester)) return yield new Tester();
    }


function* Tester(){
    console.log('but we never execute this generator function');
    }

Tester.prototype = {
    model : function*(){
        // other functions
        }
    }

It's been stumping me for hours now! I feel like the solution is super simple but I cannot seem to wrap my head around it. I have tried to simply make the Tester() function the export, but am still having the same issue. Why can't I seem to yield to the Tester() function?

Also, what may an alternative be to this approach? I want to maintain the Object nature of the module so that the module can be loaded with different inputs, such as the s_id variable/object in the example above.

aamirl
  • 1,420
  • 2
  • 12
  • 18

1 Answers1

1

a Node module (using harmony) that upon loading by another module/application, has to be yielded to so that things in it's construct can be executed and loaded before any of it's exposed functions can be called

Don't do that. Generators are not made for asynchrony. yield doesn't do what you want here. A module is not "yielded" to await something in it to load. yield is magic, but not async magic.

If you must use an asynchronous module loading process, export a promise for your actual module. That is a standard interface for something to await, and can be consumed using a standardized approach that does not rely on internals of your module.

You still can use yield syntax for constructing that promise, just use your favorite coroutine library.

return yield new Tester();
…
function* Tester(){…}

Uh oh. Well yes, apparently it is possible to call generator functions as constructors. But believe me, it is not what you want. A constructor for an arbitrary object should return that object, instead of an iterator (just like it shouldn't return a promise). If some of your object methods are generator methods, that's fine, but your constructor should be not.

If you really want to use a generator function in your code like that (and it's not meant to be a constructor), you

  • will need to yield* the iterator you've created (tester()) instead of yielding it
  • must not overwrite its .prototype property like you did, as that causes the iterator to malfunction. (Of course you should never do that at all, even though most of the time it works)
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • This is an interesting post - it raises a lot of questions for me. Our team has been using generators primarily as async functions, since the pause and resume functionality for all intents and purposes simulates asynchronous behavior. While you said that they are not 'made' for asynchrony, I think that they are used for that purpose quite often. For example: http://davidwalsh.name/async-generators . Why do you suggest against using them as such? – aamirl Apr 25 '15 at 21:59
  • Yes, they can be used for asynchrony, and that's fine (by "made for" I meant primary purpose). Only, they always form a promise, which is the standard async interface. You should export that, not some custom generator-for-async. Those modules that depend on yours should not need to know that you are using generators to implement asynchrony, hide your implementation. – Bergi Apr 26 '15 at 10:37