ES6 Promises have a curious ability to accurately retrieve values from custom JavaScript objects

I have developed a unique library that functions independently from the Promise API, yet achieves similar objectives. It utilizes window.requestAnimationFrame and fallbacks to setTimeout, having no similarities with Promises. Interestingly, it is compatible with older systems such as ie9 - 10 or machines from 2009. You can find the source code here.

Surprisingly, the following code operates smoothly, enabling the 2nd promise to transmit the value (v + 3) correctly to the 3rd promise after a delay of 10 seconds. This is due to rafx.async... returning a custom proprietary object.

const x = Promise.resolve()
.then(() => console.log("2nd promise"))
.then(() => {
  //600 frames === 10 secs
  return rafx.async(6)
  .skipFrames(600)
  .then(v => v + 1)
  .then(v => v + 3);
});

console.log(x instanceof Promise);

x.then(v => console.log("3rd promise", v));
<script src="https://cdn.jsdelivr.net/npm/rafx"></script>

The expected outcome at x.then(v...) should align with whatever custom object is returned from the custom then method.

This is the result of rafx.async(6).skipFrames(600)...then(v => v + 3):

prt.Thenable {....
    status: Status {thenable: prt.Thenable, instance: Rafx...
    _argObj: {value: 10, done: true},
    _breaker: {value: false}
    ....

The constructors Thenable and Status are completely distinct from Promises, being entirely customized.

To my surprise, this even works:

const x = Promise.resolve()
.then(() => console.log("2nd promise"))
.then(() => {
  return rafx.async("hello")
  .loop(function(str){
    return str;
  })
  .until(str => window.testVar === " world!")
  .then(str => str + window.testVar);
});

console.log(x instanceof Promise);

x.then((value) => console.log("3rd promise", value))
.catch((e) => console.log(e));
<script src="https://cdn.jsdelivr.net/npm/rafx"></script>
<button onclick="window.testVar = ' world!';">set testVar to ' world!'</button>

You can confirm that Promise.prototype.then !== rafx.Thenable.prototype.then, indicating complete separation in implementation, as shown here;

How does Promise comprehend the functionality of my API? (I must be overlooking something obvious)

PS: I replaced all arrow functions (due to this binding) with regular ones, and it still functions, albeit against expectations..

Answer №1

The Promises specification is created in a way that allows it to function alongside other "thenables", which are objects with a .then property that is a function. If you resolve a promise with a thenable (such as by returning a thenable within a .then block), the outer promise will execute that function, passing in a resolve and reject function, and will wait for the inner thenable to invoke resolve before resolving itself.

For instance:

const promise = new Promise((resolve, reject) => {
  const myThenable = {
    then: (resolve2, reject2) => {
      console.log('running .then')
      setTimeout(() => {
        console.log('resolving inner');
        resolve2("hello");
      }, 1000)
    }
  }

  console.log('resolving outer');
  resolve(myThenable);
})

promise.then(result => {
  console.log('final result', result);
})

The code you've implemented for your thenable may not have been intended for this purpose, but it seems to be functioning correctly:

prt.Thenable.prototype.then = function(f, rest){

When the promise triggers your .then function, f acts as the resolve function, while rest serves as the reject function. At some point, you call f, which coincidentally behaves as needed, without causing any unexpected exceptions when rest turns out to be a different function than anticipated.

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

Assign the DatePicker Object to an HTML Element

I am currently using a SyncFusion date picker in my project and the implementation looks like this: var datepicker = null; $("#datepicker").hide(); $("#click").click(function(){ $("#datepicker").show(); datepicker = new ej.calendars.DatePi ...

Executing the event handler only once

In my React project, I have a button that toggles a boolean state. However, I realized that the button can both set and unset the state due to its toggle functionality. I only want the state to be changed once. Is there a different function I can use ins ...

Experience the captivating AUTOPLAY feature of the mesmerizing FULLSCREEN SLIT SL

I am currently utilizing a slider that is functioning well, however I am encountering an issue with autoplay. Whenever I click on the navigation arrow or Nav dot at the bottom of the slider, the autoplay feature stops working. For more information, please ...

The scrolling event on the div is not triggering

I'm struggling with this piece of code: const listElm = document.querySelector('#infinite-list'); listElm.addEventListener('scroll', e => { if(listElm.scrollTop + listElm.clientHeight >= listElm.scrollHeight) { th ...

Exploring the magic of Hover effects using CSS and JQuery

I am exploring ways to enhance the display of an element when hovering over it. I have implemented a button and my objective is for the first click to activate the hover effect, while the second click will reset it. However, I am facing an issue where the ...

Can PHP send back data to AJAX using variables, possibly in an array format?

My goal is to transmit a datastring via AJAX to a PHP page, receive variables back, and have jQuery populate different elements with those variables. I envision being able to achieve this by simply writing: $('.elemA').html($variableA); $('. ...

Create a PDF document using a combination of charts and tables

When I try to create a PDF file with both the chart and table embedded, only the table is showing up. Can someone please provide me with some suggestions on how to resolve this issue? JSFIDDLE LINK ...

Delayed Passport Session Login

Every time I try to log in, my Express app loads very slowly... I've implemented Passport and Express Validator, but there are no errors. However, the login process for some users is extremely slow. Can anyone offer assistance? Below is a snippet o ...

How do I reduce the size of a WinJS image file

Can anyone help me figure out how to retrieve the size (in pixels, bytes) of a picture in a Windows 8 app? I'm using openPicker to select the file but can't seem to find the size attributes. I want to display an error message if the file is too ...

Is it possible to append an "index" to a database field using Express, Loopback, or NodeJS?

Currently, we are utilizing the Express/Loopback Framework for our backend. I am currently working on ensuring that indexes on certain fields in models are properly created in MongoDB. Is there a way to utilize meta-tags within the models so that DataJuggl ...

Personalizing the look of Stripe Payment Component in a React Application

Currently, I have integrated the Stripe Payment Element into my React application using the code snippet below: import { useStripe, useElements, PaymentElement, } from '@stripe/react-stripe-js' export const PaymentDetails = () => { const st ...

Transform a PNG image with transparency into a JPEG file using imagemagick

Consider utilizing the imagemagick npm module for your image manipulation needs. In the task of converting a .png file with a transparent background to a .jpeg with a white background, you may encounter challenges. Here is an example: const ImageMagick ...

The continual appearance of "No file found" persists when utilizing the $redirectRoute

My goal is to make one of the links on my website lead to another page within the site. Below is one of the two links found on my index.html page: <html ng-app="myApp"> . . . <body> <h1>My Home Page</h1> ...

Is there any way to extract the source files from a compiled Electron application?

Is there a way to extract the contents of a .app Application developed using Electron for Mac OS? I'm eager to explore the underlying source files, but I'm not familiar with the procedure to access them. Any assistance would be greatly appreciate ...

Error in React-router: Unable to assign value to the 'props' property as it is undefined

Currently, I am working on setting up routing with Meteor using the react-router package. However, I have encountered a specific TypeError: Here is a link to an image that provides more context: This is the code snippet from my main.js file: import Reac ...

Looking for a quick guide on creating a basic RESTful service using Express.js, Node.js, and Mongoose?

As a newcomer to nodejs and mongoDB, I've been searching high and low on the internet for a tutorial that combines express with node and mongoose. What I'm specifically looking for is how to use express's route feature to handle requests and ...

Elevating the Material Design Lite Progress bar using ReactJS

I currently have MDL running with React and it appears to be functioning properly. The Progress Bar is displaying on the page as expected, loading with the specified progress on page load when a number is entered directly: document.querySelector('#qu ...

What is the best way to invoke the first exported function from the second exported function?

I am looking to create a file containing four or five exported functions. exports.firstFunction = function() { // some code }; exports.secondFunction = function() { // need to call firstFunction }; My issue is that I want the second expo ...

Tips for overlapping children in a column flex direction while maintaining the parents' positioning

Currently, I am working with two parent flex items, arranged with flex-direction: column. Within the first parent, there are two children. However, one of the children is optional and may be removed at times. I aim to have the optional child displayed on ...

Error: The function gethostname has not been declared

I attempted to set a variable using gethostname() (1) and with $_SERVER(2), but I always receive an error message saying ReferenceError: gethostname is not defined. My goal is simply to fetch the current system name into a variable using JavaScript within ...