Promise represents an asynchronous operation that is not yet complete, but will be completed in the future.
There are three states of Promise
- Pending: Initial state, not yet known results
- Fulfilled: Represents successful operation
- Rejected: Representative operation failed
If the Promise operation is fulfilled or rejected, and the corresponding handler is declared, the handler function is called.
Promise vs Events Listener (Event listener)
Event listeners are good at handling recurring events on the same object, such as keystrokes, mouse clicks, and so on. For these events, you only care about what happens after you add the callback function. When processing a result-oriented asynchronous event, your code might be
Img1.callthisifloadedorwhenloaded (function() { // loaded}). Oriffailedcallthis (function() { // failed}); // and ... Whenallthesehaveloaded ([Img1, Img2]). CallThis (function() { // all Loaded}). Orifsomefailedcallthis (function() { // one or more failed });
To achieve the same functionality, Promise's code is more concise and more intuitive.
Img1.ready (). Then (function() { // loadedfunction() { // failed}); // and ... Promise.all ([Img1.ready (), Img2.ready ()]). Then (function() { // all Loadedfunction() { // one or more failed});
Promise and event listeners are similar except for the following points
1. Promise only undergoes one execution, success or failure. The Promise is not executed a second time, nor can the execution result be changed, that is, execution fails from success to failure, and vice versa. The event listener can be executed repeatedly.
2. If Promise has completed, succeeded or failed, and then adds the corresponding callback function to Promise, then the corresponding callback function will still be executed. That is, after Promise adds a callback function, the callback function checks to see if the event has occurred before it is added, executes if it occurs, and waits if it does not occur. The event listener is only responsible for events that have been added, ignoring events that were before they were added.
The above two points are very advantageous for handling result-oriented asynchronous events. Because you only need the result of a relationship event, success or failure, without knowing exactly when the event occurred.
Use of Promise
Promise already exist in some libraries, such as
Create Promise
Most of the Promise implementations in the class library follow the standard behavior, promises/a+. But the API can be a little different. Javascript comes with a Promise that uses a similar rsvp.js API.
var New Promise (function(resolve, Reject) { // do a thing, possibly async, then ... if (/**/) { resolve ("Stuff worked!") ); } Else { reject (Error ("It broke"); });
The Promise constructor takes a callback function as a parameter. The callback function is executed when the Promise object is created. Depending on the result of the callback function, either succeeds or fails, the execution controller is given the reolve () or Reject () function. However, the time reolve () or reject () is being executed after they have been added through Promise.then ().
Using Promise
Promise.then (function(result) { // "Stuff worked!" function (Err) { // Error: "It Broke"});
Promise.then () accepts two parameters, one for handling Promise execution success, and another for handling Promise failures. Two parameters are optional, so you can just pass the function to the first argument, to handle Promise success, or just pass the function to the second parameter, to handle the Promise failure.
Chained calls (chaining)
Promise.prototype.then () and Promise.prototype.catch () return a Promise, so a chained call can be formed. Chained calls can be used for value passing, or subsequent asynchronous operations in turn.
Value passing
var New Promise (function(resolve, reject) { Resolve (1);}); Promise.then (function(val) { /// 1 return val + 2 ;}). Then (function(val) { // 3});
When then () simply calls another function, you can simply pass the function name of the other function. For example
Get (' Story.json '). Then (function(response) { return json.parse (response);}). Then (function(response) { Console.log ("Yey json!") , response);});
can be simplified to
Get (' Story.json '). Then (Json.parse). Then (function(response) { Console.log ("Yey json!" , response);});
The actual combat code is as follows
function Getjson (URL) { return get (URL). then (json.parse);}
concatenating multiple asynchronous operations
If then returns a value, the next then will accept the value to continue execution. If then returns an object of another Promise, then the next then waits until the returned Promise executes (succeeds or fails).
Getjson (' Story.json '). Then (thefunction(story) {return Getjson (story.chapterurls[0 ]);}). Then (function(chapter1) { console.log ("Got Chapter 1!") , Chapter1);});
To send a Story.json request, the result is a story object containing multiple chapter URLs. The JSON data is requested again based on the first chapter URL. After successful execution, the Console.log is run last.
Example
A target resource Story.json is known and needs to be implemented in the following steps
1. Send a request to Story.json to get the URL of each chapter,
2. Send a request to each section URL to obtain the respective chapters
3. Add chapter content to an HTML page
Synchronizing Request data
Because it is a synchronous request, all requests are blocked in turn. The page is also blocked during the request and no other action is taken. This approach allows for data loading, but the user experience is poor.
Try { var story = Getjsonsync (' Story.json '); Addhtmltopage (story.heading); Story.chapterUrls.forEach (function(chapterurl) { var chapter = Getjsonsync (chapterurl); Addhtmltopage (chapter.html); }); Addtexttopage ("All Done");} Catch (Err) { addtexttopage ("Argh, Broken:" + err.message);} Document.queryselector ('. Spinner '). Style.display = ' None ';
Promise Asynchronous Request data
Getjson (' Story.json '). Then (function(story) {addhtmltopage (story.heading); //todo:for each URL in Story.chapterurls, Fetch & Display}). Then (function() { //and we ' re all done!Addtexttopage ("All Done");}).Catch(function(err) {//Catch Any error that happened along theAddtexttopage ("Argh, Broken:" +err.message);}). Then (function() { //Always hide the spinnerDocument.queryselector ('. Spinner '). Style.display = ' None ';});
Above is a framework code that loads each chapter of the functionality of each implementation. Because the array's foreach function is not an asynchronous operation, it is not possible to simply use foreach to make an asynchronous request for each chapter. You can convert an array to a Promise queue to achieve the traversal effect.
// Start off with a promise this always resolves var sequence = promise.resolve (); // Loop through our chapter URLsStory.chapterUrls.forEach (function(chapterurl) { // Add These actionsto the end of the sequence sequence = Sequence.then (function() {
return Getjson (chapterurl); }). Then (function(chapter) { addhtmltopage (chapter.html); });});
or use Array.reduce to achieve
// Loop through our chapter URLsstory.chapterUrls.reduce (function(sequence, chapterurl) { // Add These actionsto the end of the sequence return sequence.then (function
() { return Getjson (chapterurl); }). Then (function(chapter) { addhtmltopage (chapter.html); });}, Promise.resolve ());
Combine the framework code and the code that loads the chapters.
Getjson (' Story.json '). Then (function(story) {addhtmltopage (story.heading); returnStory.chapterUrls.reduce (function(sequence, chapterurl) {//Once the last chapter ' s promise was done ... returnSequence.then (function() { //... fetch the next chapter returnGetjson (Chapterurl); }). Then (function(chapter) {//and add it to the pageaddhtmltopage (chapter.html); }); }, Promise.resolve ());}). Then (function() { //and we ' re all done!Addtexttopage ("All Done");}).Catch(function(err) {//Catch Any error that happened along theAddtexttopage ("Argh, Broken:" +err.message);}). Then (function() { //Always hide the spinnerDocument.queryselector ('. Spinner '). Style.display = ' None ';});
The effect of the implementation is as follows:
Now, you can perform asynchronous, nonblocking loading of data sequentially, and load first. However, this loading method also has the space to optimize.
Promise Optimized version 1
Load the data in parallel, all loaded and displayed at the same time. The effect is as follows
Promise Optimized version 2
Load the data in parallel, showing each of the completed chapters in sequence according to the chapter order. The effect of this loading method is final. When using Chrome, it feels like data is loading quickly, and guessing is the way data is loaded.
The effect is as follows
The last two optimized versions of ideas and code reference JavaScript Promise, Jake Archibald
Resources
Promise-javascript | MDN
JavaScript Promise, Jake Archibald
[Javascript] Promise