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 until
readyState
Change to 4 after the browserBack to theheadadjustablewithrequest.onreadystatechange
Delta 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.onreadystatechange
That’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
- 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
- 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
- No specificationThere are many names used by people
success + error
And someone withsuccess + fail
And someone withdone + fail
- Prone to callback hell, code becomes unreadable
- 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, so
then
The 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, then
then
The returned Promise will be the accepted state, and the accepted state callback will take the value ofundefined
. - Throw an error, then
then
The 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, then
then
The 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, then
then
The 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
), thenthen
The 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.all
Asynchronous 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.all
Fast 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…