Understanding JS Promises

后端 未结 7 1104
梦如初夏
梦如初夏 2020-11-29 05:50

I would like to get a deeper understanding of how Promises work internally. Therefore I have some sample code:

var p1          


        
相关标签:
7条回答
  • 2020-11-29 06:32

    Let's start with an easy perspective: "chainPromises" returns a promise, so you could look at it this way:

    // Do all internal promises
    var cp = chainPromises();
    
    // After everything is finished you execute the final "then".
    cp.then(function(val) {
        console.log(val);
    });
    

    Generally speaking, when returning a promise from within a "then" clause, the "then" function of the encapsulating promise will be marked as finished only after the internal "then" has finished.

    So, if "a" is a promise, and "b" is a promise:

    // "a"'s "then" function will only be marked as finished after "b"'s "then" function has finished.  
    var c = a.then(function () {
        return b.then(function () {
            console.log("B!");
        };
    };
    
    // c is a promise, since "then" always returns a promise.    
    c.then(function() {
        console.log("Done!");
    };
    

    So the output will be:

    B! 
    Done!
    

    Notice btw, that if you don't "return" the internal promise, this will not be the case:

    // "a"'s "then" function will only be marked as finished without waiting for "b"'s "then" to finish.  
    var c = a.then(function () {
        // Notice we're just calling b.then, and don't "return" it. 
        b.then(function () {
            console.log("B!");
        };
    };
    
    // c is a promise, since "then" always returns a promise.    
    c.then(function() {
        console.log("Done!");
    };
    

    Here we can't know what would be outputted first. It could be either "B!" or "Done!".

    0 讨论(0)
  • 2020-11-29 06:32

    Promise then return promise object, not promise's resolved value. I forked your JsFiddle, and added some of mine try this.

    promise.then is executed right after that promise object is resolved.

    0 讨论(0)
  • 2020-11-29 06:33

    Normally code is synchronous - one statement executes like (fileopen) and there is a guarantee that the next statement will execute immediately afterwards like filewrite()

    but in asynchronous operations like nodejs, you should assume that

    • you have no idea when the operation will complete.
    • You can't even assume that just because you send out one request first, and another request second, that they will return in that order
    • Callbacks are the standard way of handling asynchrnous code in JavaScript
    • but promises are the best way to handle asynchronous code.
    • This is because callbacks make error handling difficult, and lead to ugly nested code.
    • which user and programmer not readble easily so promises is the way
    0 讨论(0)
  • 2020-11-29 06:37

    You can think of Promise as a wrapper on some background task. It takes in a function which needs to be executed in the background.

    The most appropriate place to use a promise is where some code is dependent on some background processing and it needs to know the status of the background task which was executed. For that, the background task itself accepts two callback resolve and reject in order to convey its status to the code which is dependent on it. In layman terms, this code is the one behind it in the promise chain.

    When a background task invokes resolve callback with some parameter. it's marking the background operation successful and passing the result of the background operation to the next then block which will be executed next. and if it calls reject, marking it as unsuccessful then the first catch block will be executed. In your custom promise, you can pass an error obj to the reject callback so that next catch block is aware of the error happened in the background task.

    0 讨论(0)
  • 2020-11-29 06:43

    Please check the below example regarding how promises works:

    The Promise object represents the eventual completion (or failure) of an asynchronous operation, and its resulting value.
    

    console.log('person1: shoe ticket');
    console.log('person2: shoe ticket');
    
    const promiseGirlFriendBringingTickets = new Promise((resolve, reject) => {
    	setTimeout(() => {
    		resolve('ticket');
    	}, 3000);
    });
    
    promiseGirlFriendBringingTickets.then((t) => {
    	console.log(`person3: show ${t}`);
    })
    
    console.log('person4: shoe ticket');
    console.log('person5: shoe ticket');

    0 讨论(0)
  • 2020-11-29 06:44

    About Promise resolution

    The thing you're witnessing here is called recursive thenable resolution. The promise resolution process in the Promises/A+ specification contains the following clause:

    onFulfilled or onRejected returns a value x, run the Promise Resolution Procedure [[Resolve]](promise2, x)

    The ES6 promise specification (promises unwrapping) contains a similar clause.

    This mandates that when a resolve operation occurs: either in the promise constructor, by calling Promise.resolve or in your case in a then chain a promise implementation must recursively unwrap the returned value if it is a promise.

    In practice

    This means that if onFulfilled (the then) returns a value, try to "resolve" the promise value yourself thus recursively waiting for the entire chain.

    This means the following:

    promiseReturning().then(function(){
        alert(1);
        return foo(); // foo returns a promise
    }).then(function(){
        alert(2); // will only run after the ENTIRE chain of `foo` resolved
                  // if foo OR ANY PART OF THE CHAIN rejects and it is not handled this 
                  // will not run
    });
    

    So for example:

    promiseReturning().then(function(){
        alert(1);
        return Promise.resolve().then(function(){ throw Error(); });
    }).then(function(){
        alert("This will never run");
    });
    

    And that:

    promiseReturning().then(function(){
        alert(1);
        return Promise.resolve().then(function(){ return delay(2000); });
    }).then(function(){
        alert("This will only run after 2000 ms");
    });
    

    Is it a good idea?

    It's been the topic of much debate in the promises specification process a second chain method that does not exhibit this behavior was discussed but decided against (still available in Chrome, but will be removed soon). You can read about the whole debate in this esdiscuss thread. This behavior is for pragmatic reasons so you wouldn't have to manually do it.

    In other languages

    It's worth mentioning that other languages do not do this, neither futures in Scala or tasks in C# have this property. For example in C# you'd have to call Task.Unwrap on a task in order to wait for its chain to resolve.

    0 讨论(0)
提交回复
热议问题