ES6 's promise by the pit

Source: Internet
Author: User
Tags delete key

Angry, Sina Weibo also too pits, code snippets too troublesome.

Promise's introduction is not much to say.
Several web sites:
http://es6.ruanyifeng.com/#docs/promise
http://www.html5rocks.com/zh/tutorials/es6/promises/
Https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Next look how to be pit.
First of all, the reason for the pit, mainly is that jquery deferred object and promise is the same API, so there has been no in-depth research, using jquery also used to, has abandoned the promise in-depth study.

It turns out that a taste is shameful and most likely to be a pit.

Code 1 is as follows.

    var error = true;
    function test () {
        //promise handles the callback of an asynchronous function, where simply using an error to represent the correct result and the condition of the unexpected result
        var promise = new Promise (function ( Resolve,reject) {
            settimeout (function () {
                if (!error) {
                    Resolve ("yes");
                } else{
                    reject ("error");
                }
            },100)
        });
        The test function internally handles unintended results. return
        Promise.catch (function (Error) {
            Console.log ("failed: +error);}"
        ;
    } Test (). Then (function (str) {
        Console.log ("Successful: +str";
    });

When the error is false, the output results

It worked: Yes.

When the error is true, the output results

Failure:
undefined: The success of the mistake

Then I was dumbfounded, what ah, why obviously failed, the successful callback will also be called.
And then start crazy Google.

See an answer is:

When no new error is thrown in the catch function, promise that the error has been resolved.

Naïve I thought I found the root of the problem, so I simply changed it to code 2.

    var error = true;
    function test () {
        var promise = new Promise (function (resolve,reject) {
            settimeout (function () {
                if (!error) {
                    Resolve ("yes");
                else{
                    reject ("error");
                }
            },100)
        });
        Return Promise.catch (function (Error) {
            //Yes, just change it here
            throw new error ("failed:" +error)
        });
    }
    Test (). Then (function (str) {
        Console.log ("Successful: +str";
    });

And then rerun, and the result becomes

Uncaught (in Promise) Error: failed: Wrong

What a ghost this uncaught is. Is it clear that the front is not to throw an exception? Why is there a catch?
So I started to question my spelling.
And I'm starting to change to code 3:

    var error = true;
    function test () {
        var promise = new Promise (function (resolve,reject) {
            settimeout (function () {
                if (!error) {
                    Resolve ("yes");
                else{
                    reject ("error");
                }
            },100)
        });
        Promise.catch (function (Error) {
            throw new error ("failed:" +error)
        });
        return promise;
    }
    Test (). Then (function (str) {
        Console.log ("Successful: +str";
    });

The result becomes:

Uncaught (in Promise) Error: failed: Error
uncaught (in promise) wrong

What the heck. Why change to this type of writing after another uncaught.
I was completely stunned at the moment. began to doubt their worldview, that they are how careless, sure where the writing is wrong, and then repeat the above three basic introduction of the example, in contrast to their writing, never found the problem.

To this step, I thoroughly messy, at one time think this promise is what ghost things, not as jquery deferred it. The hand on the delete key hesitated for a long time to change back to jquery's deferred object.

Fortunately, I finally refrained from the impulse, and took a serious look at the introduction.
Finally understand the reason.

Promise is a chained callback in which each then or catch returns an already processed promise object, while a catch can only catch errors that occur in the chain before it.

That combination of the above description, which means that my catch function is written inside the test function, so it is the first link in this chain callback, which can only catch the branch of the reject in the Promise executor, In code 1, because the Reject branch is caught, promise thinks the error has been processed and will naturally continue to invoke the then callback.
In code 2, because the error was thrown back in the catch, and there was no error in the then after the catch, there was a uncaught error message.
In code 3, changed the writing, return is the original Promise object, so in fact, catch and then are the first chain, in the catch because of the new error thrown, so there is a uncaught hint, The callback of reject is not defined in then, and the catch callback is not added after then, so a second uncaught hint is thrown.

The problem has finally been found.
So the correct code should be

    var error = true;
     function test () {
        var promise = new Promise (function (resolve,reject) {
            settimeout (function () {
                if (!error) {
                    Resolve ("yes");
                else{
                    reject ("error");
                }
            },100)
        });
        Return promise
    }
    Test (). Then (function (str) {
        Console.log (success: "+STR);}"
    . catch (function (error) {
        Console.log ("failed:" +error)
    });

That is, move the catch in code 1 to the back of the then. The results are expected to be the result of the operation.

Failure: Wrong

The problem, however, is that if you add catch callback later, according to the previous theory, the next catch, because the previous reject has been processed, so the second catch should not run, does that mean that the wrong callback can only be written once?
Change to code 4.

    var error = true;
    function test () {
        var promise = new Promise (function (resolve,reject) {
            settimeout (function () {
                if (!error) {
                    Resolve ("yes");
                else{
                    reject ("error");
                }
            },100)
        });
        Return promise
    }
    Test (). Then (function (str) {
        Console.log (success: "+STR);}"
    . catch (function (error) {
        Console.log ("failed:" +error)
    }). catch (function (error) {
        Console.log ("Second callback:" +error);
    };

The results are:

Failure: Wrong

Sure enough, the second catch was not running.
What if I join a then after this? What will be the result.
Code 5

Failed: Wrong
second successful callback: wrong

So far the basic understanding of promise chain rules.
1. Each callback accepts the return value of the previous response callback as an argument, and in code 5, because the response is the first catch callback, the callback of the second then is responded to after the error is processed, while the second then argument is the first catch The return value of the callback. If error is false, the second then parameter becomes the return value of the first then.
2. The catch function can only catch the reject that occurred before the chain, and the error of the browser is considered to be the reject state, and the reject content is the error hint.

The two-point jquery deferred is different from the promise implementation.
jquery's deferred fail function is responsive when errors occur, regardless of where they are written in the chain. Also, each callback parameter is a value of the original resolve or reject.

Now, back to the first question I wanted to solve, if I wanted to unify the reject in the test function, and the test function, only accept the resolve state how it was implemented.

To achieve this, it is also very simple, only to ensure that the catch is not after then, that is, the code 2 in the throw part of the processing error can be changed. So it's changed into code 6.

    var error = true;
    function test () {
        var promise = new Promise (function (resolve,reject) {
            settimeout (function () {
                if (!error) {
                    Resolve ("yes");
                else{
                    reject ("error");
                }
            },100)
        });
        Promise.catch (function (Error) {
            Console.log ("failed:" +error) return
            error;
        })
        return promise;
    }
    Test (). Then (function (str) {
        Console.log (succeeded: +STR);
    })

When I was elated to understand, the result gave me a fright

Failed: Wrong
uncaught (in promise) wrong

What birds, why there are uncaught hints.
To be cool, first of all, uncaught means that there is no catch in the reject state, and that the place where there is no catch is only possible after the then outside the test function. According to the previous theory, code 6 in the writing, after the catch I returned to the original Promise object, and the original Promise object reject state is actually no catch. That's why there are uncaught prompts.

So, well, you can only discard the effects of jquery's deferred.
If the error is to be handled in test, it can only be handled in an asynchronous function, that is, the reject of the settimeout is removed, leaving only the resolve, and each then handles the resolve and returns the argument directly as the return value.

However, there is no way to invoke the wrong callback again outside of Test.

Well, it seems that my requirements are more around, and the requirement itself is consistent with the functionality of jquery's deferred.

However, in order not to use jquery and satisfy my needs, it is only possible to do a more winding solution, the ultimate solution is

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.