Do JavaScript Promises operate asynchronously?

Can we clarify if JavaScript Promise is asynchronous? I've been researching Promise and async programming, particularly with ajax requests. If Promise isn't inherently async, how can we make it so?

For instance, consider a function that encapsulates another function f along with an argument array args within a Promise. The nature of f itself isn't asynchronous.

function getPromise(f, args) {
 return new Promise(function(resolve, reject) {
  var result = f.apply(undefined, args);
  resolve(result);
 });
}

In order to introduce asynchronicity, I came across recommendations on using the setTimeout method to prevent blocking in code.

function getPromise(f, args) {
 return new Promise(function(resolve, reject) {
  setTimeout(function() { 
   var r = f.apply(undefined, args);
   resolve(r);
  }, 0);
 });
}

Could the utilization of setTimeout indeed render the code non-blocking within the context of a Promise?

(Please note that no third-party Promise APIs are being relied upon, only those supported by browsers).

Answer №1

It seems like there may be a misunderstanding here. JavaScript code is always* blocking because it operates on a single thread. However, the asynchronous coding style in JavaScript allows for external operations like I/O to occur without blocking the main thread. It's important to note that even though these operations are asynchronous, the callback handling the response still blocks other JavaScript from running concurrently.

* With the exception of running multiple processes or using WebWorkers in a browser context.

Now, onto your specific questions:

Just to clarify: is JavaScript Promise asynchronous?

No, the callback provided to a Promise is executed immediately and synchronously. However, you can use Promises to handle asynchronous tasks such as timeouts or file writes, allowing you to wait for those tasks to complete before resolving the Promise.

Will using setTimeout inside a Promise make the code non-blocking?

No, using setTimeout in this way simply changes the order of execution. The rest of your script will continue to run until completion before the setTimeout callback is triggered.

For further clarification:

    console.log( 'a' );
    
    new Promise( function ( ) {
        console.log( 'b' );
        setTimeout( function ( ) {
            console.log( 'D' );
        }, 0 );
    } );

    // Other synchronous stuff, that possibly takes a very long time to process
    
    console.log( 'c' );

In this example, the output will always be:

a
b
c
D

The setTimeout callback will only execute after everything else has completed, meaning it does not make the code truly non-blocking.

Answer №2

Although this question is 7 years old, it's still relevant:

Solution:

  • The Promise block operates synchronously
  • The Promise callback blocks (resolve, reject) are synchronous
  • The call callback (not the block itself) can be asynchronous if a setTimeout block is used within the Promise block

Therefore, to directly address Jane Wayne's inquiry, using a setTimeout block will render the Promise block non-blocking.

Clarification:

Javascript functions synchronously with just one thread. The Javascript engine employs a stack called the Call Stack to execute tasks in Last In First Out (LIFO) order.

On another note, there exist Web APIs within the browser environment, such as setTimeout found within the Window object.

Communication between these two worlds is facilitated by two queues - Microtask and Macrotask queues, that follow a First In First Out (FIFO) model, managed by the Event Loop running continuously.

Event Loop, Microtask and Macrotask queues

The process unfolds as follows:

  • Execute all script through the Call Stack
  • The Event Loop constantly checks if the Call Stack is empty
  • If an empty Call Stack is detected, callbacks from the Microtask queue are pushed to the Call Stack
  • Once the Microtask queue is cleared, the Event Loop works on the Macrotask queue

Now, delving into the world of Promises:

  • The Promise block executes synchronously
  • Within the Promise block, anything executed outside the Javascript engine (like a setTimeout block) is deemed asynchronous since it runs outside the main Javascript thread.
  • While the execution of Promise callbacks (resolve and reject) may seem asynchronous, the core block remains synchronous

Hence, without any asynchronous components inside the Promise block or its callbacks, the Promise tends to halt your execution.

For instance:

console.log(`Start of file`)

const fourSeconds = 4000

// Non-blocking execution due to being added to the Macrotask queue
// Microtasks take precedence so all Promises without setTimeout go first
setTimeout(() => {
    console.log(`Callback 1`)
})

// Blocking execution because the Promise block is synchronous
// However, the result will only show after the Call Stack clears
// This becomes the first Microtask printed
new Promise((resolve, reject) => {
    let start = Date.now()
    while (Date.now() - start <= fourSeconds) { }
    resolve(`Promise block resolved`)
}).then(result => console.log(result))

// Non-blocking execution, goes to the Macrotask queue due to setTimeout
// Will pause all subsequent Macrotasks in the queue
// In this scenario, it pauses the printing of Macrotask "Callback 2"
new Promise((resolve, reject) => {
    setTimeout(() => resolve(`Promise callback block resolved`))
}).then(result => {
    let start = Date.now()
    while (Date.now() - start <= fourSeconds) { }
    console.log(result)
})

// Non-blocking execution, added to the Macrotask queue
// Microtasks hold priority over it
// Previous Macrotasks also delay its execution, hence it is last to run
setTimeout(() => {
    console.log(`Callback 2`)
})

// Non-blocking execution, enters the Microtask queue overriding setTimeout
// Previous microtasks have prime importance
Promise.resolve(`Simply resolved`).then(result => console.log(result))

console.log(`End of file`)

/*

Output:
 
Start of file
[... execution blocked 4 seconds ...]
End of file
Promise block resolved
Simply resolved
Callback 1
[... execution blocked 4 seconds ...]
Promise callback block resolved
Callback 2

*/

Answer №3

const p = new Promise((resolve, reject) => {
  if (1 + 1 === 2) {
    resolve("A");
  } else {
    reject("B");
  }
});

p.then((name) => console.log(name)).catch((name) => console.log(name));
console.log("hello world");

Asynchronous behavior of Promises allows for non-blocking execution of subsequent code lines while the promise is in pending state.

Answer №4

Thank you for the helpful MDN reference! Running this code will display output asynchronously.

================================================================ asynchronous implementation using Promises

const log = console.log;

//---------------------------------------

class PromiseLab {

    play_promise_chain(start) {
        const promise = new Promise((resolve, reject) => {      
            resolve(start);
        });     
        promise.then((start) => {
            log(`Value: "${start}" -- adding one`);
            return start + 1;
        }).then((start) => {
            log(`Value: "${start}" -- adding two`);
            return start + 2;
        }).then((start) => {
            log(`Value: "${start}" -- adding three`);
            return start + 3;
        }).catch((error) => {
            if (error) log(error);
        });             
    }
        
}

//---------------------------------------

const lab = new PromiseLab();
lab.play_promise_chain(100);
lab.play_promise_chain(200);

Output should be asynchronous like:

Value: "100" -- adding one
Value: "200" -- adding one
Value: "101" -- adding two
Value: "201" -- adding two
Value: "103" -- adding three
Value: "203" -- adding three

================================================================ Synchronous implementation using custom MyPromise class

const log = console.log;

//---------------------------------------

class MyPromise {
    
    value(value) { this.value = value; }
    
    error(err) { this.error = err; }
    
    constructor(twoArgFct) {
        twoArgFct(
            aValue => this.value(aValue),
            anError => this.error(anError));    
    }
    
    then(resultHandler) { 
        const result = resultHandler(this.value);
        return new MyPromise((resolve, reject) => {     
            resolve(result);
        });
    }
    
    catch(errorHandler) { 
        errorHandler(this.error());
    }
    
}

//--------------------------------------
    
class MyPromiseLab {

    play_promise_chain(start) {
        const promise = new MyPromise((resolve, reject) => {        
            resolve(start);
        });     
        promise.then((start) => {
            log(`Value: "${start}" -- adding one`);
            return start + 1;
        }).then((start) => {
            log(`Value: "${start}" -- adding two`);
            return start + 2;
        }).then((start) => {
            log(`Value: "${start}" -- adding three`);
            return start + 3;
        }).catch((error) => {
            if (error) log(error);
        });             
    }
        
}

//---------------------------------------

const lab = new MyPromiseLab();
lab.play_promise_chain(100);
lab.play_promise_chain(200);

Output should be synchronous:

Value: "100" -- adding one
Value: "101" -- adding two
Value: "103" -- adding three
Value: "200" -- adding one
Value: "201" -- adding two
Value: "203" -- adding three

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

Creating seamless scrolling in ReactJS without any pre-built components

Can anyone guide me on how to implement an infinite scroll in reactJs using a JSON dataset? I prefer building it from scratch without relying on any library. {data?.map((conto) => { return ( <Suspense key={conto._uid} fallback={<p>Loadin ...

Utilize JavaScript to extract content from a text file and showcase it in a Bootstrap modal pop-up through knockout binding

I'm currently working on a function that reads data from a .txt file (located in the website's root directory) and then displays it in a modal dialog box. I believe I've made progress as the file is recognized during debugging, but unfortuna ...

Getting the length of child elements in Angular using ngFor loop

Can anyone help me figure out how to check the length of a child element in my Angular *ngFor loop? I am fetching data from a real-time firebase database. What am I doing wrong? Here is the code snippet I am using: <div *ngFor="let event of events"> ...

Tips on incorporating an item into an array solely when a specific condition is met

Consider the following arrow function that creates an array: const myFunction = () => ["a", "b", "c"]; I am looking to modify this function to add another element if a specific argument is true. For example, I want it to look like this: const myFunc ...

Effortlessly move and rearrange various rows within an HTML table by utilizing JQuery alongside the <thead> elements

My JsFiddle has two tables and I want to switch rows <tr> between them using Jquery. However, due to the presence of the <thead> tag, it is not functioning properly. I suspect that the issue lies with the items in the selector, but I am unsure ...

toggle between utilizing the page object API and the primary Nightwatch API

Currently, I am incorporating the page object model alongside nightwatch for my testing procedures. Encountering challenges while trying to interact with an element led me to execute some jquery. However, the 'execute' command is not featured in ...

Having trouble receiving any ringing status in nextjs while utilizing the getstream SDK

I attempted to integrate the getstream video SDK for calling from the caller to the callee. While I can successfully create calls from the caller side, I am not receiving any status updates about the call on the callee side. Below are my codes for the cal ...

Having trouble figuring out how to load images into a div based on the current page location?

Looking for a solution to my problem - I have a navigation bar with a fixed div (A) on the far right side. The nav bar remains at the top of the page. There are 6 sections in the body of the page, each being 1200px tall divs. What I want is for a different ...

Can JavaScript event listeners be compelled to trigger in a specific sequence?

Is there a way in JavaScript to receive notification or execute a callback function once an event has completed its propagation? Put differently, is it possible to 'prioritize' an event and ensure that it gets triggered after all other event lis ...

Delete the file containing Mongoose references

I'm facing an issue with deleting questions when a survey is deleted in the Survey model. Even after deleting the survey, the question remains intact in the database. Survey Schema: let surveyModel = mongoose.Schema( { Title: String, T ...

retrieve JSON object from deferred response of AJAX request

After utilizing Ajax to send an item to a SharePoint list, I aim to incorporate the jsonObject received in response into a list of items. Located in AppController.js $scope.addListItem = function(listItem){ $.when(SharePointJSOMService.addListIte ...

What is preventing me from using .bind(this) directly when declaring a function?

Consider the code snippet below: function x() { this.abc = 1; function f1() { alert(this.abc); }.bind(this) var f2 = function b() { alert(this.abc); }.bind(this); } I am curious about how to make the "this" of the out ...

Adjust the size of both the right and left price scales on TradingView Lightweight Charts

Is it possible to set a fixed width for both the right and left price scales on a chart? Let's say, 50 pixels for the right price scale and 70 pixels for the left price scale? For a working example, please visit https://jsfiddle.net/TradingView/cnbam ...

Is it possible to retrieve only the attributes in an array?

https://i.sstatic.net/E1DMb.png I am working with an array that has properties embedded within it. I am wondering if there is a method to separate out these properties from the array data and transform them into a distinct object containing only the prope ...

When using JQuery, data may not be displayed in another function even when using the same command

Hello, I'm new here and encountering a strange problem with two functions in my script. Let me show you the first function: $(document).on("click", "#result2 p", function(){ var inv_id = $(this).text(); $.get("autocomplete_inv.php", ...

Organize routes into distinct modules in Angular 6

Currently grappling with routing in my Angular 6 application. Wondering if the structure I have in mind is feasible. Here's what it looks like: The App module contains the main routing with a parent route defining the layout: const routes: Routes = ...

Black-colored backdrop for Mui modal

Currently working with a mui modal and encountering an issue where the backdrop appears as solid black, despite setting it to be transparent. I attempted to adjust the color to transparent, but the issue persists. ...

There was an issue with the JSON parsing process due to an unexpected token 'o' at position

Trying to extract titles from a JSON object for a specific feature, here's an example of the JSON structure: [ { "title": "Example 1", "url": "http:\/\/www.example1.com\/" }, { "title": "Example 2", "url": "http:& ...

VueJS fails to display table information

I am facing an issue with rendering data from my API using VueJS 2. Although the backend services are successfully sending the data, the HTML table does not display it. There are no errors shown in the debug console, and even the Vue Debug extension for Fi ...

Having trouble with ReactJS: Why is this.setState not working?

Hello there, I am currently learning ReactJS and struggling with an issue where I keep getting the error message "this.setState is not a function". constructor() { super(); this.state = { visible: false, navLinesShow: true }; ...