0

Suppose the next piece of code:

var co = require('co');

var myObj = {
    getFieldValue: function() {
        var self = this;
        console.log(JSON.stringify(self));
        if (!self.fieldValue) {
            return function(cb) {
                // Emulate an async database load
                setTimeout(function() {
                    self.fieldValue = "the value from the database\n";
                    cb(null, self.fiedValue);
                }, 5000);
            };
        } else {
             return function(cb) {
                cb(null, self.fieldValue);
            };
        }
    },
};

co(function *() {
    var v1 = yield myObj.getFieldValue();
    console.log(v1);
    var v2 = yield myObj.getFieldValue();
    console.log(v2);
});

As you can see, I define myObj with a single method getFieldValue. The first time this methods is called, it loads the value from the database. The value is cached and, in subsequent calls, it returns the value directly. The solution works great, but the user of the object must run in a generator context and write a yield in front of each access to the object methods.

I can assume that all calls will be done in a generator context. But is there a way to rewrite the myObj implementation so that the user does not need to include the yield keyword?

I would like the user could write some thing like this (without the yields):

co(function *() {
    var v1 = myObj.getFieldValue();
    console.log(v1);
    var v2 = myObj.getFieldValue();
    console.log(v2);
});
jbaylina
  • 4,408
  • 1
  • 30
  • 39
  • Would implementing a `next()` method using the ES6 iterator protocol solve the problem, e.g., https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#Simple_iterator – user5321531 Mar 27 '15 at 14:16
  • Why would you avoid the `yield`s? They're the key element of the generator, and allow asynchronous resumption at all? – Bergi Mar 27 '15 at 15:44
  • @Bergi Because it is "dirty". I would like to use the same api of myObj without caring if it is implemented synchronously or asynchronously. var myObj = { getFieldValue: function() { return this.fieldValue; } } – jbaylina Mar 27 '15 at 16:16
  • @jbaylina: Then always return a promise. – Felix Kling Mar 27 '15 at 16:22
  • @FelixKling Well in this case I use thunks instead of promises, but I believe that it is about the same. (I don't know if you can give an example...) – jbaylina Mar 27 '15 at 16:27
  • I see... so what's the issue then? Just let the user consume thunks like they are meant to be consumed. They don't have a do use a generator (+ yield), they could just use `myObj.getFieldValue()(function(error, val) { ....});`. Your desired result is impossible to achieve. – Felix Kling Mar 27 '15 at 16:32
  • 1
    Just for reference. There is a big discussion about that in https://esdiscuss.org/topic/does-async-await-solve-a-real-problem – jbaylina Mar 28 '15 at 08:55
  • @jbaylina: If you have read that, then you surely know why `yield` is necessary? It is required when you want to consume an async result, serving as an explicit marker where the flow may yield control. – Bergi Mar 28 '15 at 12:49
  • @Bergi Yes, a yield is necessary in ECMA6 or an await in ECMA7. I just made a proposal to change the implicit behavior of the call to an async function in ECMA7 here: https://gist.github.com/jbaylina/692d4e43329c8c0d22dd. For me makes more sense.. . – jbaylina Mar 28 '15 at 19:21
  • 1
    @jbaylina: To me, it seems ridiculous to make blocking implicit. But let's discuss this at github (or esdiscuss if you've posted it there). – Bergi Mar 28 '15 at 19:44
  • possible duplicate of [Why couldn't popular JavaScript runtimes handle synchronous-looking asynchronous script?](http://stackoverflow.com/q/25446353/1048572) – Bergi Mar 29 '15 at 23:29

1 Answers1

0

If it helps, I recently took the first release of the rogue written for UNIX in C and rewrote it for javascript to work in a browser. I used a technic called continuation to be able to wait for key entry by the user because in javascript the are no interrupts.

So I would have a piece of C code like this:

void function f() {

  // ... first part

  ch = getchar();

  // ... second part

}

that would be transformed in

function f(f_higher_cont) {

  // ... first part

  var ch = getchar(f_cont1);

  return;
  // the execution stops here 

  function f_cont1 () {

    // ... second part
    f_higher_cont();
  }
}

the continuation is then stored to be reuse on a keypressed event. With closures everything would be restarted where it stoped.

Dominique Fortin
  • 2,212
  • 15
  • 20
  • 1
    This is the way of doing regular async calls in javascript. What I am asking is a different thing. Any way, thank you very much for the answer. – jbaylina Mar 27 '15 at 16:23