Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Promise A+ Implementation: what to do when call then() and the promise is still pending?

I've being working confortably with promise implementations for some time now.

So I've decided to implement my own promise library just for the fun (and learn something in the process too).

I'm trying to follow the Promise A+ specs (maybe I'll leave some details out, because I'm not meaning to make this a production code).

My full code (still in progress) is in this gist, but the relevant parts are bellow.

I'm facing a problem implementing then(). I simply don't know what to do when the promise is pending:

Promise.prototype.then = function(onFulfill, onReject) {
    var ret;
    var self = this;

    if (isFulfilled.call(this)) {
        console.log('fulfilled');
        if (isFunction(onFulfill)) {
            return promiseResolution(this, onFulfill(this.value));
        } else {
            return new Promise(function(resolve){
                resolve(self.value);
            });
        }
    } else if (isRejected.call(this)) {
        console.log('rejected');
        if (isFunction(onReject)) {
            return promiseResolution(this, onReject(this.reason));
        } else {
            return new Promise(function(resolve, reject){
                reject(self.reason);
            });
        }
    } else if (isPending.call(this)) {
        console.log('pending');
        enqueueCallback(this.fulfillCallbackQueue, onFulfill);
        enqueueCallback(this.rejectCallbackQueue, onReject);
        // ... what now?
    }
};

function promiseResolution(promise, x) {
    if (promise === x) {
        throw new TypeError('Cannot resolve promise with itself');
    } else if (x instanceof Promise) {
        if (isFulfilled.call(x)) {
            return new Promise(function(resolve, reject){
                resolve(x.value);
            });
        } else if (isRejected.call(x)) {
            return new Promise(function(resolve, reject){
                reject(x.reason);
            });
        } else {
            return x;
        }
    } else {
        return new Promise(function(resolve, reject){
            resolve(x);
        });
    }
}

The answer must be quite obvious, but I'm kind of mind-blocked here.

Edit:

I've updated the gist with the test suite I'm writing.

Edit #2:

I was able to sucessfully run the tests for a first implementation. This is the git repository where I've stored my code. I'll try to keep improving it.

Thank's to @BenjaminGruenbaum.

like image 718
Henrique Barcelos Avatar asked Dec 31 '25 02:12

Henrique Barcelos


1 Answers

First of all - make sure you're not implementing A+ unless you have a very good reason to do just that. It is very tricky to make a good promise implementation.

When the promise is pending - push the following to a handler array:

  • the promise you're returning - because Promises A+ requires you detect a promise returning itself and reject on that.
  • the reject function for the promise you extract from the constructor.
  • the resolve function for the promise you extract from the constructor.
  • the onFulfilled handler
  • the onRejected handler.

When the promise that returns the new promise undergoes resolution, you need to

  • if it rejected - run the rejection handler and resolve when it's done (reject if it threw). Check for the same reference on the return value. If there is no handler or it is not a function - you can pass e => { throw e; } instead.
  • if it fulfilled - run the fulfillment handler and resolve when it's done (reject if it threw). Check for the same reference on the return value. If there is no handler or it is not a function - you can pass v => v instead.

Of course, resolve itself needs to perform assimilation, as well as from foreign thenables. I recommend running against the promises/A+ test suite and work it out bit by bit until all tests pass.

like image 78
Benjamin Gruenbaum Avatar answered Jan 02 '26 15:01

Benjamin Gruenbaum



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!