DEV Community

Mitchell
Mitchell

Posted on

Promises/A+ & Async await - JavaScript challenges

You can find all the code in this post at the repo Github.


Async programming Promises/A+ & Async await related challenges


Implement Promises/A+ with Promise.finally()

class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onFulfilledCallbacks.forEach((callbackFn) => callbackFn(this.value));
      }
    } 

    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach((callbackFn) => callbackFn(this.reason));
      }
    }

    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }

  handlePromiseResult(result, resolve, reject) {
    if (result instanceof MyPromise) {
      result.then(resolve, reject);
    } else {
      resolve(result);
    }
  }

  then(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function'
      ? onFulfilled
      : (value) => value;
    onRejected = typeof onRejected === 'function'
      ? onRejected
      : (reason) => { throw reason; };

    // return a promise
    return new MyPromise((resolve, reject) => {
      const fulfilledHandler = () => {
        queueMicrotask(() => {
          try {
            const result = onFulfilled(this.value);
            this.handlePromiseResult(result, resolve, reject);
          } catch (err) {
            reject(err);
          }
        });
      };

      const rejectedHandler = () => {
        queueMicrotask(() => {
          try {
            const result = onRejected(this.reason);
            this.handlePromiseResult(result, resolve, reject);
          } catch (err) {
            reject(err);
          }
        });
      };

      if (this.state === 'fulfilled') {
        fulfilledHandler();
      } else if (this.state === 'rejected') {
        rejectedHandler();
      } else {
        this.onFulfilledCallbacks.push(fulfilledHandler);
        this.onRejectedCallbacks.push(rejectedHandler);
      }
    });
  }

  catch(onRejected) {
    return this.then(null, onRejected);
  }

  finally(onFinally) {
    if (typeof onFinally !== 'function') {
      return this.then();
    }

    return this.then(
      (value) => MyPromise.resolve((onFinally()).then(() => value)),
      (reason) => MyPromise.resolve(onFinally()).then(() => { throw reason })
    );
  }

  static resolve(value) {
    return new MyPromise((resolve) => resolve(value));
  }

  static reject(reason) {
    return new MyPromise((_, reject) => reject(reason));
  }
}

// Usage example
const promise = MyPromise.resolve(1);
promise.then((value) => {
  console.log(value);
})
.then(() => {
  throw new Error('Error');
})
.catch((err) => {
  console.log(`Error catched: ${err}`);
});
Enter fullscreen mode Exit fullscreen mode

Implement async await with generator

function asyncGenerator(generatorFunc) {
  return function (...args) {
    const generator = generatorFunc(...args);

    return new Promise((resolve, reject) => {
      function handle(iteratorResult) {
        if (iteratorResult.done) {
          resolve(iteratorResult.value);
          return;
        }

        Promise.resolve(iteratorResult.value)
          .then(
            (value) => handle(generator.next(value)),
            (err) => handle(generator.throw(err)),
          );
      }

      try {
        handle(generator.next());
      } catch (err) {
        reject(err);
      }
    });
  }
}

// Usage example
function* fetchData() {
  const data1 = yield fetch('https://jsonplaceholder.typicode.com/posts/1').then(res => res.json());
  console.log(data1);

  const data2 = yield fetch('https://jsonplaceholder.typicode.com/posts/2').then(res => res.json());
  console.log(data2);
}

// Create an async version of the generator function
const asyncFetchData = asyncGenerator(fetchData);

// Call the async function
asyncFetchData()
  .then(() => console.log('All data fetched!'))
  .catch(err => console.error('Error:', err));
Enter fullscreen mode Exit fullscreen mode

Reference

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more