HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Pledge: Promise-like entities design goals experiment

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
designlikepromisegoalspledgeexperimententities

Problem

Background

I was writing a promises/a+ implementation, just for fun. About halfway through I decided it wasn't that fun after all, so I decided to do something a little different.

Thinking of promises as a pattern (and not a contract), I figured they basically amount to the following (if I'm missing the point, please correct me):

-
They "flatten" async* code, avoiding callback hell.

-
They allow sensible error handling on async code.

-
They are composable, and can be chained.

-
If one promise resolves to another, that new promise must also resolve before the rest of the chain resolves (e.g. a then function returning a promise).

* I get that promises themselves don't care about async, I'm thinking more about what people use them for.

Design goals

Instead of trying to conform to the promises/a+ spec, I decided to try to create something that would allow for using a similar pattern without worrying about the promise contract. I thought it would be interesting to learn:

-
Can something as powerful as promises can be implemented in a simpler / more minimal way?

-
What improvements can be made on a promise-like pattern?

-
Is it reasonable to try to integrate promises with other promise-like things?

The first two points basically boil down to ditching the design contract idea (having a special interface for everything that returns a promise) and making a system that works better with the more common function-takes-a-callback style interfaces.

The third point is handled by having "thenable" entities that work with Promise.resolve, and by recognizing and resolving other "thenables" passed from one entity to another.

Promise-like entities

The Pledge API is similar to the Promises API.

Static methods

Use this instead of invoking the constructor.

-
Pledge.resolve(callback)

Create a new pledge, return it, and resolve it after the current script finishes.

Instance methods

Use these on objects returned from Pledge.create and Pledge.resolve.

Solution

Very interesting question.

From a high level perspective, the code gets a bit hairy from Internal stuff on, which means the API is quite clear.

I really only have nitpickings;

-
This code could have been shorter if the Pledge constructor could take the vows parameter:

function create(vows) {
    var pledge = new Pledge();

    pledge.vows = vows;

    return pledge;
}


could be

function create(vows) {
    return new Pledge( vows );
}


-
This: in a format suitable for an argument passed to a vow function. and this if (value.length == 1) { value = value[0]; drive me nuts. I dont understand from the code why you need this, and the comments are not helping me understand this either. You have this array shifting in both argValue and listValue, you could have a common helper function here

-
I got stuck on this:

return self.vows && self.vows.length || 0;


consider writing this for readability

return ( self.vows && self.vows.length ) || 0;


especially since you use compiler afterwards

-
In setReady(self), the naming could be better, if self is a pledge, why not call the parameter pledge ? Since a pledge has vows why not call completion -> vow. Compare and contrast

function setReady(self) {
    var completion;

    self.ready = true;
    while ((completion = self.pending.pop())) {
        completion();
    }
}


and

function setReady(pledge) {
    var vow;

    pledge.ready = true;
    while ((vow = pledge.pending.pop())) {
        vow();
    }
}


  • In resolveArgs as well, I would replace self with pledge, things become far more clearer.



All in all, I like the code, it is more readable than other Promise libraries that I tried to grok.

Code Snippets

function create(vows) {
    var pledge = new Pledge();

    pledge.vows = vows;

    return pledge;
}
function create(vows) {
    return new Pledge( vows );
}
return self.vows && self.vows.length || 0;
return ( self.vows && self.vows.length ) || 0;
function setReady(self) {
    var completion;

    self.ready = true;
    while ((completion = self.pending.pop())) {
        completion();
    }
}

Context

StackExchange Code Review Q#51710, answer score: 3

Revisions (0)

No revisions yet.