2

I'm trying to implement my own promise in JavaScript. Below is my class.

const states = {
    PENDING: "pending",
    FULFILLED: "fulfilled",
    REJECTED: "rejected"
}

class MyPromise {
    constructor(computation) {
        this.state = states.PENDING
        this.value = undefined;
        this.error = undefined;

        this.thenQueue = [];

        if(typeof computation === 'function') {
            setTimeout(() => {
                try {
                    computation(
                        this.onFulFilled.bind(this),
                        this.onReject.bind(this)
                    );
                } catch(ex) {
                    this.onReject.bind(this);
                }
            });
        }
    }

    then = (fullfilledFn, catchFn) => {
        const promise = new MyPromise();
        this.thenQueue.push([promise, fullfilledFn, catchFn]);
        if(this.state === states.FULFILLED) {
            this.propageFulFilled()
        } else if(this.state == states.REJECTED) {
            this.propageRejected();
        }
    }

    catch = (catchFn) => {
        return this.then(undefined, catchFn);
    }

    onFulFilled = (value) => {
        if(this.state === states.PENDING) {
            this.state = states.FULFILLED;
            this.value = value;
            this.propageFulFilled();
        }
    }

    onReject = (error) => {
        if(this.state === states.PENDING) {
            this.state = states.REJECTED;
            this.error = error;
            this.propageRejected();
        }
    }

    propageFulFilled = () => {
        for(const [promise, fullFilledFn] of this.thenQueue) {
            const result = fullFilledFn(this.value);
            if(typeof result === 'MyPromise') {
                promise.then(
                    value => promise.onFulFilled(value),
                    error => promise.onReject(error)
                )
            } else {
                promise.onFulFilled(result);    // final result
            }
        }
        this.thenQueue = [];
    }

    propageRejected = () => {
        for(const [promise, undefined, catchFn] of this.thenQueue) {
            const result = catchFn(this.value);
            if(typeof result === 'MyPromise') {
                promise.then(
                    value => promise.onFulFilled(value),
                    error => promise.onReject(error)
                )
            } else {
                promise.onFulFilled(result);    // final result
            }
        }
        this.thenQueue = [];
    }
}

If I call the code below, it works fine

const testPromise = new MyPromise((resolve, reject) => {
    setTimeout(() => resolve(10));
});

const firstCall = testPromise.then((value) => {
    console.log(value)
    return value+1;
});

However, if I add a second then to my firstCall request as below:

const firstCall = testPromise.then((value) => {
    console.log(value)
    return value+1;
}).then((newVal) => {
    console.log(newVal)
});

I got the error TypeError: Cannot read property 'then' of undefined. Does anyone know why it is happening?

Thanks

myTest532 myTest532
  • 2,091
  • 3
  • 35
  • 78
  • in your `.then()` method should return `this` which is own instance, this is so that you can create a `chain` function, something like this https://stackoverflow.com/a/7730373/9816472 – Isaac Aug 24 '21 at 02:00
  • `.then()` has to return a new promise that is chained to the current one. – jfriend00 Aug 24 '21 at 05:44

1 Answers1

1

Your then function is not returning anything:

then = (fullfilledFn, catchFn) => {
    const promise = new MyPromise();
    this.thenQueue.push([promise, fullfilledFn, catchFn]);
    if(this.state === states.FULFILLED) {
        this.propageFulFilled()
    } else if(this.state == states.REJECTED) {
        this.propageRejected();
    }
    return promise;
}
Amir MB
  • 3,233
  • 2
  • 10
  • 16
  • If I do this, I don't get the error, but it does not work properly. ```const testPromise = new MyPromise((resolve, reject) => { setTimeout(() => resolve(10)); }).then((value) => { console.log(value) return 2*value; }).then((newVal) => { console.log(newVal) });``` It prints 10 two times. The second call should be 20 – myTest532 myTest532 Aug 24 '21 at 02:28
  • `.then()` has to return a new promise that is chained to the original one, not return the original promise. – jfriend00 Aug 24 '21 at 05:45
  • I got it. Thank you – myTest532 myTest532 Aug 24 '21 at 19:19