The Promise object is used for deferred (deferred) and asynchronous (asynchronous) computations. This article mainly and everybody to share javascript/node.js in the promises detailed, hoped can help everybody.
One Promise in one of the following three states:
Pending: Initial state, non-fulfilled or rejected.
Fulfilled: successful operation.
Rejected: failed operation.
The Promise interface is represented as a proxy for a value that may not be known when Promise is created. It allows you to associate handlers with the final success or failure state of an asynchronous action. This allows an async method to return a value like a synchronous method: An Async method returns a promise that has a value at some point in the future instead of the final return value.
The promise of the pending state can be either a fulfilled state with a value or a rejected state with a reason. When any situation occurs, the corresponding handlers that are arranged by Promise's then method (queued up) are called. (when the corresponding handler is bound, if promise is already in the fulfilled or rejected state this handler will be called, so there is no race condition between the completion of the asynchronous operation and its handler binding.)
Because the Promise.prototype.then and Promise.prototype.catch methods return promises, they can be called by chaining-an operation called composition.
Why did Promise appear?
Simply put, Promise was treated as a life-saving elixir for callback hell.
The callback function is a feature of JavaScript! node. JS's official API basically is to pass the function return value in the callback mode. Accustomed to synchronous programming of this asynchronous way how much will be acclimatized, and layers of nesting, unknowingly built a high callback pyramid. In response to this general problem, promise should be born!
Promise Basic Usage
Create Promise
Promise.then (function (result) { console.log (result);//"Perfect! "}, Function (err) { console.log (err); Error: "Problem"});
"Then" accepts two parameters, succeeds in calling one, fails to call another, and two is optional, so you can handle only successful situations or failures.
Promise Practice
Handling of values
You can make some changes to the results and return a new value:
Getjson (' Story.json '). Then (the function (story) { return Getjson (Story.chapterurls[0]);}). Then (function (chapter1) { Console.log ("Got Chapter 1!", chapter1);});
You return a "class Promise" Object
Get (' Story.json '). Then (function (response) { Console.log ("success!", Response);}, function (Error) { Console.log ("failed!", error);});
You can also use "catch":
AsyncThing1 (). Then (function () { return asyncThing2 ();}). Then (function () { return asyncThing3 ();}). catch (function (err) { return asyncRecovery1 ();}). Then (function () { return AsyncThing4 ();}, function (err) { return AsyncRecovery2 ();}). catch (function (err) { console.log ("Don t worry about it");}). Then (function () { console.log ("All done!");});
Promise API Reference
Static methods
Promise.resolve (Promise);
Returns a Promise (when and only if promise.constructor = = Promise)
Promise.resolve (thenable);
Creates a new Promise from the Thenable object. A thenable (class Promise) object is an object with a "then" method.
Promise.resolve (obj);
Create a Promise with the positive result of obj.
Promise.reject (obj);
Creates a Promise that negates the result with obj. For consistency and debugging convenience (such as stack trace), obj should be an Error instance object.
Promise.all (array);
Creates a Promise that, if and only if all Promise in the passed-in array are positive, throws a negative result if any one of the Promise in the array is encountered with a negative end. Each array element goes through Promise.resolve first, so the array can contain class Promise objects or other objects. The positive result is an array that contains the positive result (and hold order) of each Promise in the array, and the negative result is the first negative result that is encountered in the incoming array.
Promise.race (array);
Creates a Promise that, when an arbitrary object in an array is positive, ends up as a positive end, or when any object in the array is negative, the result is dismissed as a negation.
Current Solutions for Promise
In fact, there are some third-party libraries to implement the Promise function:
These libraries and JavaScript native Promise adhere to a common, standardized specification: Promises/a+,jquery has a similar method called Deferred, but not compatible with promises/a+ specifications, so there will be a little problem, use need to be cautious. JQuery also has a Promise type, which is actually a reduced version of Deferred, so there is the same problem.
The current browser has (in part) implemented the Promise.
Versions of Chrome 32, Opera 19 and Firefox 29 are supported by default for Promise. Because it is in the WebKit kernel, we have reason to expect that the next version of Safari will be supported, and IE is in continuous development.
To achieve compatible standard Promise on both browsers, or to use Promise in other browsers and node. js, you can look at this polyfill (2K after gzip).
The Comrades who play node know that when the language is mentioned, as the most proud of the asynchronous mechanism, but the PHP and Python and other war groups are not sprayed like, they laughed at the nodejs that stupid infinite nesting, Nodejs Regiment only with us as long as performance!!! to comfort themselves.
As is known to all, JavaScript as a single-threaded language, all work is blocked, and many people do not understand why the JavaScript is blocked, how can the asynchronous mechanism?
Give me a chestnut.
We can use the browser to trigger XMLHttpRequest (Ajax) to get the data asynchronously, SetTimeout, setinterval to complete the timed task, in the case we can usually access. This is not the language of JavaScript to determine these asynchronous operations, but rather to explain the JavaScript browser to operate threads for multi-threaded operations, you can interpret these methods as a browser-thrown multithreaded API. Nodejs is implemented based on high-performance V8, which is also a browser-like API that throws out a lot of threading APIs to implement asynchronous mechanisms.
The asynchronous mechanism allows us to save more system resources and does not need to open a new thread like Php,tomcat for every request, and node will have threads that handle various tasks (using many modules, such as Net,file system,timers, to manipulate different threads). Distributing different asynchronous tasks to individual task threads and flexibly assigning hardware to threads is a high performance from V8 and the root cause of why Nodejs can face high I/O situations.
Reality
In the end, we have to face the gory reality, and when I first approached node, the code wrote the same thing.
Fs.readfile (Mrfilefirst, "UTF8", function (err,data1) { if (err) { //do err thing }else{ fs.readfile ( Mrfilesecond, "UTF8", function (ERR,DATA2) { if (err) { //do err thing }else{mongo.find (Somequery, function (err,data3) { if (err) { //do err thing }else{ //do The real thing with [DATA1,DATA2,DATA3] } }) } }) }})
Oh,my god! Good asynchronous mechanism or play into sync ... and miserable! Just want to return the last three data, but this example three tasks do not have a relationship between nesting, this way to force the asynchronous to play synchronous, or block code, this code of the work sequence is probably in this way:
And without node is no different, it is completely blocked. In peacetime we can meet more of the relationship level of nesting (the next step is based on the results of the previous steps), it is necessary to use synchronization to complete the task, but if it is written like this, I believe you will write to spit blood (I have forgotten that I have written in the code of several less if (err) {}, Because node's underlying API Async method takes err as the first parameter, so that all async methods in the upper layer are in this mode)
Evolution
Some people can not see, and then someone will stand out, we gradually realized the process from scratch, I first contact is Ali's
Eventproxy:
var EP = require ("Eventproxy"), Ep.create ("Task1", "Task2", "Task3", function (RESULT1,RESULT2,RESULT3) { //do the Real thing with [RESULT1,RESULT2,RESULT3]}). Fail (function (e) { //do err thing}), Fs.readfile (Mrfilefirst, "UTF8", Ep.done ("Task1")), Fs.readfile (Mrfilesecond, "UTF8", Ep.done ("Task2")), Fs.readfile (Mrfilethird, "UTF8", Ep.done (" Task3 "));
In this way, three files can be read asynchronously, and the final work is done when all three tasks are completed, such as the sequence diagram:
The three tasks are triggered almost simultaneously (minus the trigger time of the code), so the three points on the left can actually be viewed as a point, and all three tasks go asynchronously at the same time, triggering the final task when three tasks are completed.
This is where node has the advantage, and it saves a lot of time (if three tasks consume 1, then the time is reduced by 2/3), which is the big node. js.
Eventproxy also has more usage that can be seen on its npm.
Async
Async is a foreign powerful asynchronous module, its function and eventproxy similar, but maintenance speed and cycle particularly fast, after all, is used more people ah, but the support of domestic-is a feeling, with the introduction of the use of async articles
http://blog.fens.me/nodejs-async/
Re-evolution
People are always dissatisfied, and just this is not content, just let us continue to explore the want, more convenient things. At this time, someone would like to write their own code reusability is higher, but also do not want to write so many callback to nest, then there is the promiss/a+ specification, which is:
Interoperable JavaScript promises-by implementers, for implementers.
A robust universal JavaScript promise open standard, originated by developers and attributed to developers
In ES6 also added the use of native promise, and before promise Library has promise,q,bluebird, in these libraries are now slowly to ES6 native promise is compatible, although ES6 is not yet large-scale into the use of the process.
The most famous is the Bluebird and Q Library, I use Bluebird, first put a bluebird code to feel it
Bluebird:
cast//mrfileone.txt//mrfiletow.txt//mrfilethree.txt//Relationship Nesting task var Promise = require ("Bluebird"), Readfileasync = Promise.promisify (Require ("FS"). ReadFile) Readfileasync ("MrFileOne.txt", "UTF8"). Then (function (data) {//if the D ATA contains the path of mrfiletow var path = ...//do something with Data return Readfileasync (path, "UTF8 "); }). Then (function (data) {//if The data contains the path of mrfilethree var path = ...//do something W ITH data return Readfileasync (path, "UTF8"); }). Then (function (data) {//get The data of Mrfilethree//do something}). catch (function (err) { Console.log (ERR); });//No Relationship Rollup task Promise.all ([Readfileasync ("MrFileOne.txt", "UTF8"), Readfileasync ("MrFileTwo.txt", "UTF8"), Readfileasync ("MrFileThree.txt", "UTF8")]). Then (function (datas) {//do Something with three data form our Actors}). catch (function (err) {Console.log (err); });
Is there any attraction to this notation, which is the charm of the Promise module, which gracefully writes the callback of the function into the then and returns a new promise for the next time to return the result of the returned.
How
The method is used first:
Readfileasync = Promise.promisify (Rquire ("FS"). ReadFile);
This method is to replicate the ReadFile method and add a promise mechanism to it, and what is the promise mechanism? That is, after adding the Promise method and the property, the return value of the whole method is a Promise object, we can call the then method through promise to deal with the callback of this promise method. By default, the first parameter, err, is placed in the catch in the promise, so that we do not have to write so many if (err). We can get the asynchronous data of this promise directly by using the function parameter in the then method, and then proceed with the next step.
After the then method, it returns a Promise object that we can then do again to get the last then data and process it. Of course, we can also artificially determine this then's return parameter, but the entire then method returns a Promise object.
Readfileasync ("MrFileOne.txt", "UTF8") . Then (function (data) { if (...) { //data isn ' t what we want promise.reject ("It's not correct data!"); } else{ return data; } }) . Then (function () { Console.log ("yeah! We got data! "); }) . catch (function (err) { console.log (err); })
In the above code, if the obtained data is not what we want, then we can call Promise.reject directly to throw an error, and directly to the catch to handle errors, so in the console we can get "It's not correct data!", And will not get "yeah! We got data! ", because after throwing an error its subsequent then method does not follow.
More
Of course, we can also customize multiple catch to catch different error and treat it differently, just like the following
var customerror = new Error (somenumber,somedescription) readfileasync ("MrFileOne.txt", "UTF8") . Then (function ( Data) { switch (data) {case CASE1: promise.reject (customerror); Case CASE2: promise.reject (New SyntaxError ("Noooooo!")); } ) . catch (Customerror,function (err) { //do with Customerror }) . catch (Syntaxerror,function (err) { / /do with SyntaxError }) . catch (function (err) { console.log (err); })
And more ways to use, you can learn from Bluebird on NPM, I believe you will love promise after watching.
Q
Q module is also a very good promise, its implementation principle and Bluebird are similar, are based on the promise/a+ standard to expand, so the use is not even how much, choose which one to see personal interests.
Promise Programming Ideas
The point is, let's take a look at the normal code first.
var obj = (function () { var variable; return { get:function () { return variable; }, set:function (v) { variable = v; }} }) (); exports.get = Obj.get;exports.set = Obj.set;
This code is implemented to create a closure to store variables, then I call this module externally, then I can go to manipulate the value, that is, the implementation of a scope variable, and encapsulate it up.
Contradiction
According to our previous thought, this code looks very normal, but then I want to add a judgment in, that is, when the Get method is called, if Varibale is undefined, then I will do a read the file operation, from the file read it out, and back, how will you do?
You will find that you cannot do this through past thinking, so use async thinking to think about it, like a bit of a door head:
Get:function (callback) { if (Varibale) { callback (Varibale); } else{ fs.readfile ("Somefile", "UTF8", function (err,data) { if (err) { //do with err return; } callback (data);} ) }}
So ... Well, it seems as though you might be able to fix it, but you'll feel that it's really awful, and we've changed the simple get function so complicated. So the question is, who would have thought that the get method is actually a callback method when used? You usually use get when you will consider that there can be a callback? We are all directly get () to get its return value.
This is the contradiction and trouble we have caused ourselves, which I have encountered before.
Breakthrough
So in the modular node, how do we get to these unnecessary troubles? That is to use promise thought to write their own code, we first try to use the above mentioned bluebird to process this code:
var Promise = require ("Bluebird"), fs = require ("FS"); var obj = (function () { var variable; return { get:function () { if (variable) { return promise.resolve (variable); } Return Promise.promisify (Fs.readfile) ("Somefile", "UTF8"); }, set:function (v) { return Promise.resolve (variable = v);}} ); Exports.get = Obj.get;exports.set = Obj.set;
It is so beautiful, the use of the Promise.resolve method is to convert the variable into a Promise object, when we use the module externally, we require that we use the idea of promise to apply the interface thrown by the module, such as:
var module = require ("Thismodule.js"); Module.get () . Then (function (data) { console.log (data); Module.set ("New String"); return module.get; }) . Then (function (data) { console.log (data); });
When we use promise thought to face each interface, we can completely not consider the code of this module is how to write, this method how to use is right, whether it is callback or assignment. We can solve all the problems directly after the module method. Do not care about what the previous work done, how to do, in the end is asynchronous or synchronous, as long as we will use the entire workflow promise to do, it will be much easier, and the readability of the code will become better!
It's an artifact!
Using promise programming ideas to play with node, you will believe that true love is in front of you. At the same time, I also believe that in the front-end modular acceleration today, promise programming ideas will certainly penetrate into the front of more corners.
Philip
With promise, because the most asynchronous processing in front-end code is AJAX, they are packaged to promise. Then style. What about non-asynchronous processing of a subset of synchronizations? Methods such as Localstorage, SetTimeout, SetInterval and the like. In most cases, bloggers still recommend the use of promise packaging, so that the return interface of the project service is unified. This also facilitates serial, parallel processing of multiple asynchronous tasks, as in the previous example. This is also the case with the angular route for setting template only.
For settimeout, setinterval in angular has built the $timeout and $interval services for us, they are a promise package. What about Localstorage? The $q.when method can be used to directly wrap the return value of the Localstorage as the Promise interface, as follows:
var data = $window. Localstorage.getitem (' Data-api-key '); Return $q. When (data);
The return value of the service layer for the entire project can be encapsulated in a uniform style used, and the project becomes more consistent and unified. It is also easy and consistent to use when multiple service is required to parallel or serial processing.
Promise DSL Semantic encapsulation for deferred tasks
As mentioned earlier, promise is deferred to the future to perform certain tasks, and at the time of invocation it returns a "promise" to the consumer, and the consumer thread is not blocked. After consumers accept the "promise", consumers will not have to care about how these tasks are done, and to urge the producers of the task execution status. By the end of the mission, the "promise" in the hands of consumers was fulfilled.
For such delay mechanisms, it is also extremely common in UI interactions in the front-end. For example, the modal window display, the user in the modal window interaction results can not be predicted in advance, the user is to click on the "OK" button, or "Cancel" button, this is a future delay event will occur. The processing of such scenes is also an area that promise is good at. The implementation of the modal in Angular-ui Bootstrap is also based on the Promise encapsulation.
$modal. Open ({ templateurl: '/templates/modal.html ', controller: ' Modalcontroller ', Controlleras: ' Modal ', resolve: { }}) . Result . Then (function ok (data) { //user clicks OK button event }, function cancel () { //user clicks Cancel button event });
This is because modal gives us a promise result object (commitment) in the return value of the Open method. When the user clicks the OK button in the modal window, Bootstrap uses the $q defer to resolve to perform the OK event, and conversely, if the user taps the Cancel button, $q defer is used to perform the Cancel event.
This solves the problem of delay triggering and avoids the callback hell. We can still further semantic its return value, naming it in terms of business-owned terminology to form a set of DSL APIs.
function open (data) { var defer = $q. Defer (); Resolve or reject defer; var promise = Defer.promise; Promise.ok = function (func) { promise.then (func); return promise; }; Promise.cancel = function (func) { promise.then (null, func); return promise; }; return promise;};
We can access it in the following ways:
$modal. Open (item). OK (function (data) { //OK Logic }) . Cancel (function (data) { //Cancel Logic });
Does it feel more semantic? The return method of $http in angular success, error is also the same logic encapsulation. Registers the success registry function as a successful callback for the. Then method, and the registration method of the error registers as the failed callback for the then method. So the success and error methods are just the angular framework for the set of syntactic sugars we encapsulate on the promise syntax.
Angular the implementation code of the success, error callback:
promise.success = function (fn) { promise.then (function (response) { fn (response.data, Response.Status, response.headers, config); }); return promise; }; Promise.error = function (fn) { promise.then (null, function (response) { fn (response.data, Response.Status, response.headers, config); }); return promise; };