Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Simple Promise and Then implementation

Recently I was shown a piece of code that were asked during a full-stack developer interview. It involved creating a Promise, in which the candidate should implement, passing it a resolve function, and chaining 2 then's.

I tried implementing the Promise very naively only to make the code work. Created a ctor that accepts a resolver func, Created a Then function that accepts a callback and returns a Promise, and simply calls the callback on the resolver function.

class MyPromise {

    constructor(resolver) {
        this.resolver = resolver;
    }

    then(callback) {
        const result = new MyPromise(callback);
        this.resolver(callback);

        return result;
    }
}

promise = new MyPromise(
    (result) => {
        setTimeout(result(2), 500);
    });
promise.then(result => {
    console.log(result);
    return 2 * result;
}).then(result => console.log(result));

The expected result is 2,4 - just like operating with real Promise. But i'm getting 2,2. I'm having trouble figuring out how to get the return value for the first "then" and passing it along.

like image 877
Erez Avatar asked Apr 05 '19 11:04

Erez


Video Answer


3 Answers

Here's the shortened code for creating a promise class,

class MyPromise {
  constructor(executor) {
    this.callbacks = [];

    const resolve = res => {
      for (const { callback } of this.callbacks) {
        callback(res);
      }
    };

    executor(resolve);
  }

  then(callback) {
    return new MyPromise((resolve) => {
      const done = res => {
        resolve(callback(res));
      };
      this.callbacks.push({ callback: done });
    });
  }
}


promise = new MyPromise((resolve) => {
  setTimeout(() => resolve(2), 1000);
});

promise.then(result => {
  console.log(result);
  return 2 * result;
}).then(result => console.log(result));
like image 62
AZ_ Avatar answered Oct 23 '22 04:10

AZ_


Your question has some issues:

  • The r2 variable is nowhere defined. I will assume result was intended.
  • The setTimeout is doing nothing useful, since you execute result(2) immediately. I will assume setTimeout(() => result(2), 500) was intended.

If the code was really given like that in the interview, then it would be your job to point out these two issues before doing anything else.

One issue with your attempt is that the promise returned by the then method (i.e. result) is never resolved. You need to resolve it as soon as the this promise is resolved, with the value returned by the then callback.

Also, the promise constructor argument is a function that should be executed immediately.

In the following solution, several simplifications are made compared to a correct Promise behaviour.

  • It does not call the then callbacks asynchronously;
  • It does not support multiple then calls on the same promise;
  • It does not provide the rejection path;
  • It does not prevent a promise from resolving twice with a different value;
  • It does not deal with the special case where a then callback returns a promise

console.log("Wait for it...");

class MyPromise {
    constructor(executor) {
        executor(result => this.resolve(result));
    }
    resolve(value) {
        this.value = value;
        this.broadcast();
    }
    then(onFulfilled) {
        const promise = new MyPromise(() => null);
        this.onFulfilled = onFulfilled;
        this.resolver = (result) => promise.resolve(result);
        this.broadcast();
        return promise;
    }
    broadcast() {
        if (this.onFulfilled && "value" in this) this.resolver(this.onFulfilled(this.value)); 
    }
};

// Code provided by interviewer, including two corrections
promise = new MyPromise(
    (result) => {
        setTimeout(()=>result(2), 500); // don't execute result(2) immediately
    });
promise.then(result => {
    console.log(result); // Changed r2 to result.
    return 2 * result;
}).then(result => console.log(result));

Note the 500ms delay in the output, which is what should be expected from the (corrected) setTimeout code.

I posted a full Promises/A+ compliant promise implementation with comments in this answer

like image 40
trincot Avatar answered Oct 23 '22 04:10

trincot


How about very simple:

const SimplePromise = function(cb) {
  cb(
    data =>
      (this.data = data) &&
      (this.thenCb || []).forEach(chain => (this.data = chain(this.data))),
    error =>
      (this.error = error) &&
      (this.catchCb || []).forEach(chain => (this.error = chain(this.error)))
  );
  this.then = thenCb =>
    (this.thenCb = [...(this.thenCb || []), thenCb]) && this;
  this.catch = catchCb =>
    (this.catchCb = [...(this.catchCb || []), catchCb]) && this;
};

Example Here: https://codesandbox.io/s/0q1qr8mpxn

like image 2
Manuel Richarz Avatar answered Oct 23 '22 04:10

Manuel Richarz