Javascript uses a callback function (callback) to handle asynchronous programming. There is an adaptive process from synchronous programming to asynchronous callback programming, but if there is a multi-layer callback nesting, which is what we often call the doom-correction pyramid (Pyramid of Doom), it's definitely a bad programming experience. Then there is the Commonjs promises/a specification, which is used to solve the problem of the callback pyramid. This article first introduces the promises related specifications, and then through the interpretation of a mini promises to deepen understanding.
What is Promise
a Promise object represents a value that is not available at this time, but can be resolved at some point in the future. It allows you to write asynchronous code in a synchronized fashion. For example, if you want to use the Promise API to invoke a remote server asynchronously, you need to create a Promise object that represents the data that will be returned by the WEB service in the future. The only problem is that the current data is not available yet. When the request completes and returns from the server, the data becomes available. During this time, the Promise object will act as a proxy role for real data. Next, you can bind a callback function to the Promise object, and the callback function will be invoked once the real data becomes available.
Promise objects have existed in many languages in various forms.
The correction pyramid for the removal of Doom (Pyramid of Doom)
the most common mode of anti-modal in Javascript is callback internal and nested callbacks.
Callback Pyramid
asyncoperation (function (data) {/
/process ' data '
anotherasync (function (data2) {
//process ' data2 ')
Yetanotherasync (function () {
//Complete
});
}
);
Code after introduction of promises
Promisesomething ()
. Then (function (data) {
//process ' data ' return
anotherasync ();
})
. Then (function (data2) {
//process ' data2 ' return
yetanotherasync ();
})
. Then (function () {
//Complete
});
Promises the nested callback, resulting in a series of. Then consonant calls that go beyond the poor code style of the layers indentation. Promises is not an algorithm for solving specific problems, just a better code organization pattern. Accept the new organizational model and also gradually understand the asynchronous invocation with a new perspective.
Each language platform has the corresponding Promise realization
- Java ' s Java.util.concurrent.Future
- Python ' s Twisted deferreds and PEP-3148 Futures
- F # ' s Async
- . Net ' s Task
- C + + one ' s std::future
- Dart ' s Future
- Javascript ' s promises/a/b/d/a+
Let me take a look at some of the details of the various specifications in the JavaScript language environment.
PROMISES/A specification
Promise represents a final value that is returned when an operation completes.
- Promise has three states: * * incomplete * * (unfulfilled), * * Completion * * (fulfilled) and * * * failure * * (failed).
- The state of the promise can only be converted to completion by * * incomplete * *, or * * NOT completed * * * failed * * *.
- The Promise state transition occurs only once.
Promise has a then method, the then method can accept 3 functions as parameters. The first two functions correspond to the two states of promise fulfilled and rejected callback functions. The third function is used to process progress information (support for progress callbacks is optional).
Promisesomething (). Then (function (fulfilled) {
//When promise State becomes fulfilled, call this function
},function (rejected) {
//When the promise state becomes rejected, call this function
},function (progress) {
//When the progress information is returned, call this function
});
If promise supports the following additional methods, it is called an interactive promise
Gets a property on the current promise final value, which is a new promise.
- Call (functionname, arg1, arg2, ...)
Call Of course promise a method on the final value, and the return value is also a new promise.
promises/b specification
on the basis of promises/a, promises/b defines a set of APIs that promise modules need to implement
When (value, callback, errback_opt)
If value is not a promise, the next event loop callback is invoked and value is the passed-in value of callback. If value is a promise,promise state has completed or becomes complete, the next event loop callback will be invoked, and the resolve value will be passed into the Callback;promise state has failed or become a failure, The next event loop Errback will be invoked and reason will be passed into Errback as a reason for failure.
ASAP (value, callback, errback_opt)
When the maximum difference is that if value is not a promise, it is executed immediately and does not wait until the next event loop.
Enqueue (Task Function)
Call the task method as soon as possible in the next event loop.
Get (object, name)
Returns a promise that gets the object's properties.
Post (object, name, args)
Returns a promise that invokes the object method.
Put (object, name, value)
Returns a promise that modifies the property of an object.
Del (object, name)
Returns a promise that deletes an object property.
Makepromise (descriptor Object, fallback Function)
Returns a Promise object that must be a callable function or a constructor that can be instantiated.
- The first parameter accepts a description object, which is structured as follows,
Each of the above registered handle returns a resolved value or promise.
- The second parameter accepts a fallback (message,... args) function that is triggered when no promise object finds a corresponding handle, and returns a resolved value or promise.
Defer ()
Returns an object that contains a resolve (value) method and a Promise property.
When the Resolve (value) method is first invoked, the state of the Promise property becomes complete, and the state of the promise that observes the promise before or after it is converted to completion. The value parameter, if not a promise, is wrapped into a promise ref. The Resolve method ignores all subsequent calls.
Reject (reason String)
Returns a promise that is marked as failed.
One of the following two methods is used when a promise on a failed message method is called
1. If there is a errback,errback, it will be invoked as a reason parameter. The When method returns the return value of the Errback.
2. If there is no Errback,when method that returns a new reject state of the Promise object, take the same reason as the argument.
Ref (Value)
if value is a Promise object, returns the value itself. Otherwise, return a resolved promise, carrying the following handle.
1. When (errback), ignore Errback, return resolved value
2. Get (name), returns the corresponding property of the resolved value.
3. Put (name, value), set the corresponding property of the resolved value.
4. Del (name), delete the corresponding property of the resolved value.
5. Post (name, args), call the corresponding method of the resolved value.
6. All other calls return a reject and carry the reason "Promise does not handle NAME".
Ispromise (value) Boolean
determine if an object is promise
Method (name String)
gets a promise that returns the name corresponding method. The return value is the corresponding method for "get", "put", "Del" and "POST", but is returned in the next event loop.
PROMISES/D specification
in order to increase the interoperability between different promise implementations, the PROMISES/D specification makes further agreement on promise objects and promises/b specifications. To achieve the effect of the duck type (Duck-type Promise).
In simple terms, promises/d spec, doing two things,
1, how to determine an object is a Promise type.
2, the promises/b specifications to add details.
identify a Promise object
the Promise object must be the implementation Promisesend method.
1. In the context of the Promise library, if an object contains Promisesend methods, it can be screened as a Promise object
2. The Promisesend method must accept an action name as the first argument
3. The operation name is an extensible collection, and the following are some reserved names
1. When, the third parameter must be a rejection callback.
1. The rejection callback must accept a rejection reason (can be any value) as the first argument
2. Get, when the third parameter is the property name (string type)
3. Put, at this point the third parameter is the property name (string type) and the fourth parameter is the new property value.
4. Del, at this time the third parameter is the property name
5. Post, when the third parameter is the property name of the method, and the next argument is the invocation parameter of the method
6. IsDef
4. The second parameter of the Promisesend method is the resolver method
5. The Promisesend method may accept the argument
6. The Promisesend method must return to undefined
Supplement to the Promises/b specification
In the PROMISES/D specification, the ref, Reject, Def, defer methods defined in the Promises/b specification are further refined, and these details are omitted.
promises/a+ specification
The promises/a/b/d norms mentioned earlier were commonjs by organizations, Promises/a+ was issued by a self-proclaimed promises/a+ organization, supplemented and revised on the basis of promises/a, Designed to improve interoperability between promise implementations.
Promises/a+ the then method, defines the detailed promise resolution procedure process, and takes the. Then method as the object discrimination method of the promise.
In addition, promises/a+ provides compatibility testing tools to determine the compatibility of each implementation.
Implement a mini version of promise
with so many specs on it, let's look at how to implement a simple and short promise.
1. State machine
var PENDING = 0;
var fulfilled = 1;
var rejected = 2;
function Promise () {
//store state which can is PENDING, fulfilled or rejected
var state = PENDING;
Store value or error once fulfilled or rejected
var value = null;
Store sucess & failure handlers attached by calling. Then or. done
var handlers = [];
}
2. State change
Only two state transitions are supported, fulfill and reject
// ...
function Promise () {
//...
function fulfill (Result) {state
= fulfilled;
Value = result;
}
function reject (Error) {state
= rejected;
Value = error;
}
}
Fulfill and reject methods are relatively low-level, and usually more advanced resolve methods are open to the outside.
// ...
function Promise () {
//...
function Resolve (Result) {
try {
var then = Getthen (result);
if (then) {
doresolve (then.bind (Result), resolve, Reject)
return
}
fulfill (result);
} catch (E ) {
reject (e);
}
}
}
The Resolve method can accept a normal value or another promise as an argument, and if you accept a promise as an argument, wait for it to complete. Promise is not allowed to be fulfill by another promise, so an open resolve method is required. The Resolve method relies on some help methods defined as follows:
/** * Check If a value is a Promise and, if it's, * return to the ' then ' of that Promise. * * @param {promise| any} value * @return {function|
Null} */function Getthen (value) {var t = typeof value;
if (value && t = = = ' object ' | | t = = ' function ')) {var then = Value.then;
if (typeof then = = = ' function ') {return then;
} return null; }/** * Take a potentially misbehaving resolver function and make sure * onfulfilled and onrejected are only called
E. * * makes no guarantees about asynchrony. * * @param {function} fn A resolver function Trusted * @param {function} onfulfilled * @param {function
} onrejected */function Doresolve (FN, onfulfilled, onrejected) {var done = false; try {fn (function (value) {if (done) return is done = True onfulfilled (value)}, function (reason) {if (Don
e) The return is done = True onrejected (Reason)})} catch (ex) {if (done) return is done = True onrejected (ex)}}
Here the recursion between resolve and Doresolve is ingenious, which is used to process promise nesting (promise value is a promise).
Construction device
// ...
function Promise (FN) {
//...
Doresolve (FN, resolve, reject);
}
. Done method
// ...
function Promise (FN) {
//...
function handle (handler) {
if (state = = PENDING) {
Handlers.push (handler);
} else {
if (state = = FU lfilled &&
typeof handler.onfulfilled = = ' function ') {
handler.onfulfilled (value);
}
if (state = = rejected &&
typeof handler.onrejected = = ' function ') {
handler.onrejected (value);
}
}
}
This.done = function (onfulfilled onrejected) {
//Ensure we are always asynchronous settimeout
(function () {
handle ({
onfulfilled:onfulfilled,
onrejected:onrejected
});
}, 0;
} // ...
}
. Then method
// ...
function Promise (FN) {
//...
This.then = function (onfulfilled, onrejected) {
var self = this;
return new Promise (function (resolve, reject) {return
Self.done (function (result) {
if (typeof onfulfilled = = ' F Unction ') {
try {return
resolve (onfulfilled):
} catch (ex) {return
reject (ex);
} else {return
resolve (result);
}
, function (Error) {
if (typeof onrejected = = ' function ') {
try {return
Resolve (onrejected (Error)),
catch (ex) {return
reject (ex);
}}
else {
Return reject (Error)
;}});} // ...
}
$.promise
Prior to the jquery 1.8 version, the jquery then method is simply a sketch method that invokes the three callbacks of the done, fail, and progress, while the then of the PROMISES/A specification behaves more like jQuery pipe. JQuery 1.8 Fixes this problem, making then a synonym for pipe. However, because of the backward compatibility problem, the Promise of jQuery is not very attractive to promises/a.
In addition, in the PROMISES/A specification, the Promise object that is generated by the then method is either executed or rejected, depending on whether the callback called by the then method is a return value or throws an error. It is a bad idea to throw an error in the callback of the Promise object in JQuery because the error is not captured.
Summary
The last example reveals that the key to implementing Promise is to implement a good doresolve method that triggers a callback after it is finished. and in order to guarantee the asynchronous settimeout (fun, 0); is a key step.
Promise has been used quite well, and it optimizes the code structure of Nodejs asynchronous processing. But for its working principle is somewhat ignorant and curious, so spent some energy to consult and translate the Promise specification, in order to fully understand the Promise details.
The above is about the use of promise in JavaScript introduction, I hope to help you learn.