What issue could be present in my JavaScript promise setup?

I'm currently working on developing my own Promise in JavaScript to enhance my comprehension of how Promises work. I've encountered a roadblock while trying to understand the .then method and I need some guidance: I came across the documentation for the .then method here https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then, which mentions that the .then method returns a Promise. However, I'm struggling with writing this because it appears that this.result is undefined. Could someone please explain why this is happening and how I can resolve this issue?

Below is the code I'm working with:

class LitePromise {
  constructor(fn) {
    if (typeof fn !== "function") {
      throw new TypeError("Promises must be functions");
    }
    this.fn = fn;
    this.state = PENDING;
    this.result = null;
    const resolveCallback = this.resolve.bind(this);
    const rejectCallback = this.reject.bind(this);
    try {
      fn(resolveCallback, rejectCallback);
    } catch (err) {
      this.reject(err);
    }
  }

  resolve(arg) {
    console.log(arg, "arg");
    this.result = arg;
    this.state = RESOLVED;
  }

  reject() {
    this.state = REJECTED;
  }

  // create an instance of this promise
  then(callback) {
    const tinyPromise = new LitePromise(this.fn);
    console.log(callback, "callback");
    try {
      return tinyPromise.resolve(callback(this.result));
    } catch {
      return tinyPromise.reject(callback(this.result));
    }
  }
}

console.log("------------------");
const yaypromise = new LitePromise((resolve, reject) => {
  console.log("1. running");
  setTimeout(() => {
    console.log("2. resolving");
    resolve("yay");
  }, 100);
}).then((result) => {
  console.log("3. evaluating");
  if (result !== "yay") {
    console.log("It's not working yet");
    return;
  }
  console.log("SUCCESS!", result);
});

Answer №1

One of the main issues at play here is the following dilemma regarding the processing of then(). Typically, then() is handled in two distinct ways:

  1. If the promise is pending, the callback(s) passed to then() are stored and executed once the promise is resolved at a later time.
  2. If the promise has already been resolved (either successfully or with rejection), the callback provided to then() is invoked promptly.

The problem arises from not addressing the first scenario properly. If the promise resolves after calling then(), it will not function correctly.

Furthermore, the sub-promise returned from then() should only resolve once the callback's result supplied to then() is finalized.

If this explanation seems convoluted, rest assured it can be quite challenging =) I suggest focusing on mastering the logic for managing callbacks within .then() before attempting to return values from .then().

To address similar obstacles, I created my own minimalistic promise implementation. Feel free to explore it here:

https://github.com/evert/promise-demo/blob/master/src/my-promise.js

Answer №2

Below is a sample code snippet demonstrating the functionality of our custom promise:

const delay = ms =>
  new promise(r => setTimeout(r, ms))
  
const roll = n => {
  console.log("rolling...")
  return delay(1000)
    .then(_ => Math.ceil(Math.random() * n))
    .then(x => { console.log(x); return x })
}

const main = _ =>
  roll(20).then(x =>
    roll(20).then(y =>
      roll(20).then(z =>
        { console.log("three rolls:", x, y, z)
          return [x,y,z]
        }
      )
    )
  )

main()
  .then(([x,y,z]) => x + y + z)
  .then(sum => console.log("sum:", sum))
  .catch(console.error)
rolling...
12
rolling...
18
rolling...
15
three rolls: 12 18 15
sum: 45

While there are improvements that can be made to this code, understanding Promise implementation can be challenging. Here's an initial draft of our promise class:

class promise {
  constructor(exec, value, resolved = false, rejected = false) {
    this.value = value;
    this.resolved = resolved;
    this.rejected = rejected;
    this.callback = [];
    
    if (this.resolved || this.rejected) return;
    
    exec(x => this.resolve(x), e => this.reject(e));
  }

  // Other methods and static functions defined here for resolving and rejecting promises
  
}

Keep in mind that direct invocation of p.resolve or p.reject should be avoided in favor of using p.then and p.catch. The example above illustrates how these features work together.

Feel free to expand the provided code snippet in your browser to see it in action. If you have any questions or encounter errors, I'll be available tomorrow to assist further.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

I am experiencing issues with my React DND implementation in Next JS - can anyone help troubleshoot?

I'm encountering an issue with my React DND implementation. Although I am able to drag elements, they are not being received by the drop targets. I even tried using console.log in the drop function of useDrop but nothing is logging in the console on d ...

AngularJS - issue with directive functionality on dynamically inserted classes

Check out this plnkr - I've got a button that toggles the class toggled on the body element. I've also developed a directive to trigger an alert when the toggled class is applied to the body element, but for some reason it's not working. H ...

Declaring types globally in Visual Studio Code for JavaScript programming

My /typings/$app.d.ts file has the following structure: declare class App { test: object } export const $app: App; https://i.sstatic.net/3HW7M.png In order to enable intellisense, I have to auto-import it, resulting in a line like this at the begin ...

Discovering instructions on locating Material UI component documentation

I'm having trouble locating proper documentation for MUI components. Whenever I attempt to replicate an example from the site, I struggle to customize it to fit my requirements. There are numerous props used in these examples that I can't seem to ...

Combine the power of JavaScript with Node.js

I am brand new to the world of node and feeling a bit lost when it comes to finding the right solution for my current issue. I would greatly appreciate any guidance towards the best approach. Currently, I am using the Buddy framework to compile coffeescri ...

The pie chart is unable to render due to issues with accessing the external JSON file in Ext

I attempted to create a pie-chart using extjs, but unfortunately, the pie-chart is not showing up. Interestingly, when I pass the JSON data through AJAX inline, it works perfectly fine. However, when I try passing it through a file, it doesn't work a ...

Tips for implementing bslib package pop up window within a table displayed using rhandsontable in R Shiny

I am trying to implement the template from Laurent's answer on R Shiny - Popup window when hovering over icon in my code below, which involves integrating a popup window into a rhandsontable table. My goal is to display the popup window as depicted in ...

Testing the mongoose.connect callback method in Jest: A step-by-step guide

Currently working on a new Express application and utilizing Jest as the testing framework. All sections of code have been successfully covered, except for the callback of the mongoose.connect method: https://i.sstatic.net/SNrep.png I attempted to spy o ...

Retrieve a result from a setTimeout function

Can someone assist me with storing the status value in a variable named 's'? Any help would be greatly appreciated. Below is the code snippet: let s = setTimeout( ()=>{ this.matchService.getMatches().subscribe(ms => { this.match ...

A method to eliminate click events for an element

I have a unique element called #foo with a click event attached to it. This element is nested within another element called #bar, which also has a separate click event attached to it. <div id="bar"> <div id="foo" /> </div> Currently, ...

Updating data in Redux triggers a refresh of Material UI table data

Utilizing the material-ui data table component to showcase data, enabling users to update and save information via a form when clicking on a row. Implemented react-redux for state management and dispatching updated rows to the existing data. However, despi ...

The request included an unsupported media type of "text/plain;charset=UTF-8". This caused an error in the NextJS API when interacting with Django Rest Framework

Currently diving into the world of web development, I am endeavoring to construct a website utilizing NextJS and Django Rest Framework. While NextJS effectively proxies API endpoints for retrieving data, I find myself grappling with making it work for a PO ...

Issues arise when building with Angular using `ng build`, but everything runs smoothly when using `

My Angular 5 application uses angular-cli 1.6.8 { "name": "test", "version": "0.0.0", "license": "MIT", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "karma": "ng test", "test": "jest", "test:watch": "j ...

I keep receiving a 400 (Bad Request) error when trying to delete with my REST API

I've successfully created an API and have managed to make POST and GET requests work flawlessly. However, I'm facing some trouble with the DELETE request. Every time I try to execute it, I encounter a 'DELETE http://localhost:3000/api 400 (B ...

Struggling to dynamically resize 2 boxes using JavaScript

I am attempting to create a layout with two Divs side by side, each containing slightly different content. I have successfully resized them equally using JavaScript, but the issue arises when loading the collapsed content as it does not adjust to the new s ...

The function is missing from the object, leading to a script error with jQuery

When using different versions of jQuery, I encountered some issues with saving changes in my application. Initially, with jquery-1.4.4.min.js, everything worked except for the save function due to an error I made. However, when switching to jquery-1.7.1.mi ...

What is the correct way to pass parameters when using the setState() function in React hooks?

I am working on a project where I have a list of country names. When a user clicks on one of the countries, I want to update the state with the name of the newly selected country. This state change will then trigger other changes in a useEffect(). The stat ...

Reorganize the workflow in Node.js by moving the business logic from the controller to the

As I delve into learning Node.js, I've encountered a challenge with code refactoring. After researching the best practices for code architecture in Node.js, I am eager to refactor my code. The current state of my code: user.controller.js const bcry ...

What is the best way to enlarge text size with jquery?

I am attempting to: $('a[data-text="size-bigger"]').click(function () { a=$('span'); b=$('span').css('font-size'); a.css('font-size', b+1); } ); Initially, I ha ...

How can I ensure that the div remains fixed on scroll and appears directly below the navigation bar, rather than at the top of the page?

There is a div (#callback) that loads asynchronously via ajax upon submit, for updating or deleting an item. It appears as the green message box at the top of the page. Click here to see image and this is how it looks when "scrolling": Check out the scrol ...