The purpose of the Promise

synchronous

  • Straight to the results

asynchronous

  • You can’t get the results directly

Take AJAX encapsulation as an example

        ajax = (method, url, options) = > {
            const{success, fail} = options
            const request = new XMLHttpRequest()
            request.open(method, url)
            request.onreadystatechange = () = > {
                if (request.readyState === 4) {
                    if (request.status < 400) {
                        success.call(null, request.response)
                    } else if (request.Status >= 400) {
                        fail.call(null, request, request.status)
                    }
                }
            }
            request.send()
        }
        
        ajax('get'.'/xxx', {
            success(reponse){}, fail:(request, status) = >{}})Copy the code
  • request.send()After that, you can’t get it directlyresponse
  • Have to wait untilreadyStateChange to 4 after the browserBack to theheadadjustablewithrequest.onreadystatechangeDelta function, we get delta functionrequst.reponse

The callback

  • Write a function for your own use, not a callback
  • A function written for other people is called a callback
  • request.onreadystatechangeThat’s what I wrote for the browser call
  • It means that your browser goes back and calls this function
  • Call back => call back

A function that you write but don’t call and give to someone else to call

Callback and asynchronous relationships

associated

  • Asynchronous tasks need to notify JS to get the results when they get them
  • How?
  • You can ask JS to leave a function address (phone number) to the browser
  • When the asynchronous task is complete, the browser calls the address of this function.
  • And pass the result as an argument to the function (it was ready to eat on the phone)
  • This function is what I wrote for the browser to call, so it is a callback function

The difference between

  • Asynchronous tasks require callback functions to notify the result
  • But callbacks are not necessarily limited to asynchronous tasks
  • Callbacks can be used in synchronization tasks
  • array.forEach(n => console.log(n))It’s a synchronous callback

How do I know if a function is synchronous or asynchronous

If the return value of a function is

  • setTimeout
  • AJAX (both XMLHttpRequest)
  • AddEventListener

So this is an asynchronous function that AJAX can set to be synchronous. If set to synchronous, the page will freeze during the request

What if the asynchronous task succeeds or fails?

Two results

  1. The callback takes two arguments
        fs.readFile('./1.txt'.(error, data) = > {
            if(error) {
                console.log('failure'); 
                return
            }
            console.log(data.toString()) / / success
        })
Copy the code
  1. Use 1 for two callbacks
        ajax('get'.'/1.json', data() => {}, error() => {})
        // The first function is a success callback and the second function is a failure callback
        ajax('get'.'/1.json', {
            success: () = {},fail: () = >{}})// Accept an object with two keys representing success and failure
Copy the code

Deficiency in

  1. No specificationThere are many names used by peoplesuccess + errorAnd someone withsuccess + failAnd someone withdone + fail
  2. Prone to callback hell, code becomes unreadable
  3. Error handling is difficult

Callback hell example:

        getUser(user= >{
            getGroup(user, (groups) = > {
                groups.forEach((g) = > {
                    g.filter(x= > x.ownerId === user.id)
                     .forEach(x= > console.log(x))
                })
            })
        })
Copy the code

So how to solve it?

  • Specify the name or order of the callbacks
  • Avoid callback hell and make your code more readable
  • Easy to catch errors

In fact, as early as 1976, Daniel P.Friedman and David Wose proposed the idea of Promise, based on which Future, Delay and Deferred front-end combination Promise and JS were invented. I developed the Promise/A+ specification that describes in detail how Promise works and how Promise works. Again, we’ll use AJAX encapsulation as an example

        ajax = (method, url, options) = > {
            const{success, fail} = options
            const request = new XMLHttpRequest()
            request.open(method, url)
            request.onreadystatechange = () = > {
                if (request.readyState === 4) {
                    if (request.status < 400) {
                        success.call(null, request.response)
                    } else if (request.Status >= 400) {
                        fail.call(null, request, request.status)
                    }
                }
            }
            request.send()
        }
        
        ajax('get'.'/xxx', {
            success(reponse){}, fail:(request, status) = >{}})Copy the code

I’ll write it as Promise

// Change the posture of the call first
        ajax('get'.'/xxx', {
            success(response){}, fail: (request, status) = >{}})// Use two callbacks, success and fail
   
// Make a Promise
         ajax('get'.'/xxx')
             .then(response) => {}, (requset) = > {})
Copy the code

The first argument to success then is the second argument to fail. What does ajax return?

  • Returns an containing.then()Method object

How do you get it?

  • You have to modify the Ajax source code
        ajax = (method, url, options) = > {
            return new Promise ((resolve, reject) = > {
                const{success, fail} = options
                const request = new XMLHttpRequest()
                request.open(method, url)
                request.onreadystatechange = () = > {
                    if (request.readyState === 4) {
                        if (request.status < 400) {
                            resolve.call(null, request.response)
                        } else if (request.Status >= 400) {
                            reject.call(null, request)
                        }
                    }
                }
                request.send()
            })
        }
        
         ajax('get'.'/xxx')
             .then(response) => {}, (requset) = > {})
Copy the code

How do I create a New Promise

        return new Promise((resolve, reject) => {})
Copy the code

How to usePromise.prototype.then

The then() method returns a Promise (en-us). It needs at most two arguments: a callback to Promise’s success and failure cases.

        p.then(onFulfilled[, onRejected]);

        p.then(value => {
          // fulfillment
        }, reason => {
          // rejection
        });

Copy the code
  • OnFulfilled optional

  • This is a function that will be called when the Promise becomes a state of acceptance. This function takes one argument, the fulfillment value that was accepted. If the argument is not a function, it is internally replaced with (x) => x, the function that returns the promise final result as is

  • OnRejected optional

  • The function called when a Promise becomes the Rejected state. This function takes one argument, the rejection reason. If the argument is not a function, it is internally replaced with a “Thrower” function (it throws an error it received as argument).

The return value

This is a big pity. When a Promise completes or fails, the return function will be called asynchronously (scheduled by the current thread loop). The specific return value is returned according to the following rules. If the callback function in then:

  • Returns a value, sothenThe returned Promise will become the accepted state, and the returned value will be used as the parameter value of the callback that accepts the state.
  • No value is returned, thenthenThe returned Promise will be the accepted state, and the accepted state callback will take the value ofundefined.
  • Throw an error, thenthenThe returned Promise will be the rejection state, and the thrown error will be the parameter value of the rejection state callback.
  • Return a Promise that is already in an accepted state, thenthenThe returned Promise also becomes the accepted state, and the value of the Promise’s accepted state callback is used as the value of the returned Promise’s accepted state callback.
  • Return a Promise that is already in the reject state, thenthenThe returned Promise also becomes the rejection state, and the value of the Promise’s rejection state callback is used as the value of the returned Promise’s rejection state callback.
  • Returns an undetermined state (pending), thenthenThe state that returns a Promise is also undefined, and its final state is the same as the final state of that Promise; At the same time, the callback that it calls when it goes to its final state is the same as the callback that the Promise calls when it goes to its final state.

How to usePromise.all

Promise.all can wrap multiple Promise instances into a new Promise instance. Also, success and failure return different values, with success returning an array of results and failure returning the first rejected state. Promise.all waits for everything to complete (or the first failure).

var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve, reject) = > {
  setTimeout(resolve, 100.'foo');
});

Promise.all([p1, p2, p3]).then(values= > {
  console.log(values); // [3, 1337, "foo"]
});
Copy the code

If the argument contains non-promise values, those values are ignored, but are still placed in the return array (if the promise completes)

// this will be counted as if the iterable passed is empty, so it gets fulfilled
var p = Promise.all([1.2.3]);
// this will be counted as if the iterable passed contains only the resolved promise with value "444", so it gets fulfilled
var p2 = Promise.all([1.2.3.Promise.resolve(444)]);
// this will be counted as if the iterable passed contains only the rejected promise with value "555", so it gets rejected
var p3 = Promise.all([1.2.3.Promise.reject(555)]);

// using setTimeout we can execute code after the stack is empty
setTimeout(function(){
    console.log(p);
    console.log(p2);
    console.log(p3);
});

// logs
// Promise { <state>: "fulfilled", <value>: Array[3] }
// Promise { <state>: "fulfilled", <value>: Array[4] }
// Promise { <state>: "rejected", <reason>: 555 }
Copy the code

Promise.allAsynchronous and synchronous

// we are passing as argument an array of promises that are already resolved,
// to trigger Promise.all as soon as possible
var resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];

var p = Promise.all(resolvedPromisesArray);
// immediately logging the value of p
console.log(p);

// using setTimeout we can execute code after the stack is empty
setTimeout(function(){
    console.log('the stack is now empty');
    console.log(p);
});

// logs, in order:
// Promise { <state>: "pending" }
// the stack is now empty
// Promise { <state>: "fulfilled", <value>: Array[2] }

Copy the code

Promise.allFast return to failed behavior

var p1 = new Promise((resolve, reject) = > {
  setTimeout(resolve, 1000.'one');
});
var p2 = new Promise((resolve, reject) = > {
  setTimeout(resolve, 2000.'two');
});
var p3 = new Promise((resolve, reject) = > {
  setTimeout(resolve, 3000.'three');
});
var p4 = new Promise((resolve, reject) = > {
  setTimeout(resolve, 4000.'four');
});
var p5 = new Promise((resolve, reject) = > {
  reject('reject');
});

Promise.all([p1, p2, p3, p4, p5]).then(values= > {
  console.log(values);
}, reason= > {
  console.log(reason)
});

//From console:
//"reject"

//You can also use .catch
Promise.all([p1, p2, p3, p4, p5]).then(values= > {
  console.log(values);
}).catch(reason= > {
  console.log(reason)
});

//From console:
//"reject"
Copy the code

How to usePromise.race

The promise.race (iterable) method returns a Promise that is resolved or rejected once a Promise in the iterator is resolved or rejected. The race function returns a Promise that will be completed in the same way as the first Promise passed. It may be a high degree of completion or rejection, depending on which of the two is the first.

If the passed iteration is empty, the returned promise will wait forever.

If the iteration contains one or more non-promise values and/or resolved/rejected promises, promise.race resolves to the first value found in the iteration.

Race ([P1, p2]) returns the fastest result, regardless of whether the result itself is a success or a failure

let p1 = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    resolve('success')},1000)})let p2 = new Promise((resolve, reject) = > {
  setTimeout(() = > {
    reject('failed')},500)})Promise.race([p1, p2]).then((result) = > {
  console.log(result)
}).catch((error) = > {
  console.log(error)  // 打开的是 'failed'
})
Copy the code

reference

  • MDN
  • www.ituring.com.cn/article/665…
  • www.jianshu.com/p/7e60fc1be…