Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature: Synchronous prefix to solve pyramids-of-doom (while being backwards compatible) #104

Closed
gladys123 opened this issue Dec 7, 2014 · 5 comments

Comments

@gladys123
Copy link

Pyramids of doom are a common issue with the callback orientated architecture. While they can be countered in many ways, I believe there's a need for a simple, versatile, and backwards compatible feature that fixes it.

&: the call synchronously prefix.

console.log( &request('https://www.google.com').body ) is equivalent to

request('https://www.google.com', function(err, status, body){
    console.log(body);
});

Effect

Execution of the rest of the block is paused until the async function returns, making it effectively synchronous. The callback parameters are returned, as an object.

Example

Before:

socket.on("event", function(data){
    db.query("SELECT foo, bar FROM moo WHERE 1", function(err, rows){
        if (err)
            // handle
        if (rows.length){
            request('http://external.api/' + rows[0].foo, function(err, status, body){
                request('http://external.api/' + rows[0].bar, function(err2, status2, body2){
                    asyncFunction(foo, bar, function(response){
                        socket.emit("response", response);
                    });
                });
            });
        }
    });
});

After:

socket.on("event", function(data){
    var res = &db.query("SELECT foo, bar FROM moo WHERE 1");
    if (res.err)
        // handle
    if (res.rows.length){
        var fooReq = &request("http://external.api/" + res.rows[0].foo).body;
        var barReq = &request("http://external.api/" + res.rows[0].bar).body;
        socket.emit("response",  &asyncFunction(fooReq, barReq));
    }
});

Compatibility

This would allow calling any async function synchronously. It can be implemented with some simple pre-processing, without any changes to V8 and it would be 100% backwards compatible with existing code.

  • Callbacks with one return parameters will return it directly. Bonus: Resolves boilerplate if a function returns multiple parameters as an object.
  • Callbacks with multiple return parameters will return it as an object. Bonus: Parameters are order-indepedent.

Do we really need it?

I think this is the simplest solution. Pyramids of doom are faced by people new to node universally, and this resolves it without the need of any external modules.

With io.js, let's advance the platform and embrace useful change that are backwards compatible.

@madbence
Copy link

madbence commented Dec 7, 2014

Callbacks with multiple return parameters will return it as an object. Bonus: Parameters are order-indepedent.

function foo(cb) {
  setTimeout(function() {
    cb(null, 1, 2, 3);
  }, 1000);
}

console.log(&foo())

What is the logged object here? Btw, pyramid of doom is not really an issue with generators and promises (and async-await in ES7):

co(function* () {
  var content = yield get('http://google.com');
  console.log(content);
});

@indutny
Copy link
Member

indutny commented Dec 7, 2014

@gladys123 are you talking about adding this in core?

@benjamingr
Copy link
Member

@gladys123 if you want such a drastic change you'll have to take it up to TC39. I don't think this is the place to discuss such changes.

Also - I agree with what @madbence said this is practically a non-issue with promises+generators or async/await in ES7. Even today with just promises today the nesting wouldn't really be an issue. Alternatives such as the 'classic' async library or even just organizing your callbacks better could be equally effective.

@rlidwka
Copy link
Contributor

rlidwka commented Dec 7, 2014

yield is effectively the same "synchronous prefix" you're talking about

Also, you can play with sweet.js to achieve & semantics you want.

@chrisdickinson
Copy link
Contributor

@gladys123 iojs gets its javascript runtime from V8, which in term implements it according to the ECMAScript spec -- the best place to start if you want to propose changes is esdiscuss.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants