Before we start the formal introduction, we want to see what Javascript Promise looks like:
The code copy is as follows:
var p = new Promise(function(resolve, reject) {
resolve("hello world");
});
p.then(function(str) {
alert(str);
});
1. then() returns a Forked Promise
What is the difference between the following two codes?
The code copy is as follows:
// Exhibit A
var p = new Promise(/*...*/);
p.then(func1);
p.then(func2);
// Exhibit B
var p = new Promise(/*...*/);
p.then(func1)
.then(func2);
If you carefully consider the above two pieces of code equivalent, then Promises is just a one-dimensional array of callback functions. However, this is not the case. Each then() call returns a forked promise. Therefore, in ExhibitA, if func1() throws an exception, func2() is still called normally.
In ExhibitB, if func1() throws an error, fun2() will not be called because the first call returns a new promise, which will be rejected in func1(). The result is func2() being skipped.
Summary: promises can be fork into multiple paths, similar to complex flowcharts.
2. Callback should pass the result
What will get a warning when you run the following code?
The code copy is as follows:
var p = new Promise(function(resolve, reject) {
resolve("hello world");
});
p.then(function(str) {})
.then(function(str) {
alert(str);
});
The alert in the second then() does not show anything. This is because the callback function, in the context of promise, there is no callback function because the result changes. promise expects your callback to return the same result or a replacement result, which is then passed to the next callback.
Similar to using adpater to change the results, as follows:
The code copy is as follows:
var feetToMetres = function(ft) { return ft*12*0.0254 };
var p = new Promise(/*...*/);
p.then(feetToMetres)
.then(function(metres) {
alert(metres);
});
3. Only exceptions from the previous layer can be caught
What is the difference between these two pieces of code?
The code copy is as follows:
// Exhibit A
new Promise(function(resolve, reject) {
resolve("hello world");
})
.then(
function(str) {
throw new Error("uh oh");
},
undefined
)
.then(
undefined,
function(error) {
alert(error);
}
);
// Exhibit B
new Promise(function(resolve, reject) {
resolve("hello world");
})
.then(
function(str) {
throw new Error("uh oh");
},
function(error) {
alert(error);
}
);
In the first piece of code, the exception in the first then() is thrown and will be caught by the second then(), and the "uh oh" warning will be triggered. This guide only exceptions at the previous level will be caught.
In the second piece of code, the callback function and the error callback function are at the same level, which means that when an exception is thrown in the callback, it will not be caught. In fact, the error callback of the second code will only be thrown if the promise is rejected or if the promise itself is wrong.
4. Errors can be restored
In an error callback function, if you do not re-throw the error, promise assumes that you have recovered from the error and inverted to a resolved state. In the next example, "i'm saved" will be displayed because the error callback in the first then() did not re-throw the exception.
The code copy is as follows:
var p = new Promise(function(resolve, reject) {
reject(new Error("pebkac"));
});
p.then(
undefined,
function(error) { }
)
.then(
function(str) {
alert("I am saved!");
},
function(error) {
alert("Bad computer!");
}
);
Promise can be seen as a layer on an onion. Each then() adds another level to the onion. Each level represents a processed activity. When the hierarchy is finished, the result is considered to have been fixed and ready for the next hierarchy.
5. Promises can be suspended
Because you are ready to execute in one then() method, it does not mean that you cannot pause and run other in advance. In order to pause the current promise, or let it wait for another promise to complete, simply return another promise in then().
The code copy is as follows:
var p = new Promise(/*...*/);
p.then(function(str) {
if(!loggedIn) {
return new Promise(/*...*/);
}
})
.then(function(str) {
alert("Done.");
})
In the previous code, the prompt will not appear until the new promise is parsed. This is a convenient way to introduce more dependencies in the existing asynchronous code path. For example, you might find that the user session has timeout and you might want to initialize the second login before continuing with the previous code path.
6. Resolved Promises will not be executed immediately
Will you get a prompt box when running the following code?
The code copy is as follows:
function runme() {
var i = 0;
new Promise(function(resolve) {
resolve();
})
.then(function() {
i += 2;
});
alert(i);
}
Because promise is parsed immediately and then() method is executed immediately, you may think that prompt 2 will be probed. However, the promise definition requires that all calls be forced asynchronous. Therefore, the prompt will be generated before it is modified.