The core idea behind promises is that a promise represents the result of an asynchronous operation. A promise is in one of three different states:
• pending - The initial state of a promise.
• fulfilled - The state of a promise representing a successful operation.
• rejected - The state of a promise representing a failed operation.
Once a promise is fulfilled or rejected, it is immutable (i.e. it can never change again).
The resolve function returns data values, not the promise itself.
The .then function runs upon and as soon as the Promise resolves.
JavaScript Promises are a core Progressive Web App (PWA) technology and an alternative to the traditional event-listener or callback approaches to asynchronous programming.
Promises replaces nested callbacks and event handlers. It make asynchronous code easier to write and maintain. Callbacks are difficult to write and maintain. Promises makes for simple and modular code. .catch captures any errors above it.
Semi-colon is only used on last statement of promise chain.
return getImageName (country)
.then (fetchFlag)
.then (processFlag)
.then (appendFlag);Catch can also supply a default value to the next function.
.then can have two parameters for "then success" or "then error."
return getImageName (country)
.catch (fallbackName)
.then (fetchFlag)
.then (processFlag)
.then (appendFlag)
.catch (logError);Promises can be powerful but if you don’t follow proper error-handling practices, they can make life difficult. If you’ve worked on a large project that made extensive use of promises, you may have encountered some difficulties with debugging — This is because, without careful error-handling, Error objects that are thrown inside promises won’t tell you anything about the sequence of actions which led to the error; all they’ll tell you is the file and line number where the error was created.
A useful thing about catch handlers is that you can chain them:
// ...
.then((output) => {
return doAsyncOperation3();
})
.catch((err) => {
// Re-throw the error as a higher-level error.
// We will include the message from the lower-level
// error as part of the error message for this error.
throw new Error('Higher-level error. ' + err.message);
})
.catch((err) => {
// In here we will get the higher-level error.
})Being able to chain multiple catch handlers like this is particularly useful if you have a sub-module which returns a long promise chain which spills out into one or more other higher-level modules; this means that you can add a single catch at the end of each sub-chain (in each file) which simply re-throws errors into the current file’s scope. You don’t always need to refer to the previous error when re-throwing an error but it can sometimes help.
Catching and re-throwing errors in this way will tell you which higher-level module lead to the error; that means that you can later dig in and debug the issue on a layer-by-layer basis (top-down approach).
Note that the technique discussed in this article is mostly useful for handling exceptions, not unexpected errors caused by bugs in the code. To find errors caused by unexpected bugs, you need to test each code unit/module individually.
// ES6 Promises - More syntax and examples
// calling resolve directly
// calling reject directly
//
let p1 = new Promise((resolve, reject)=>{
if(true){
resolve('p1 resolved');
}else{
reject('p1 rejected');
}
});
let p2 = Promise.resolve('p2 resolved');
let p3 = () => Promise.resolve(null);
let p4 = () => Promise.reject('p4 rejected');
p1.then((result)=>{
console.log('p1:', result);
})
p2.then((result)=>{
console.log('p2:', result);
});
p3().then((result)=>{
console.log('p3:', result);
})
p4().then((result)=>{
console.log('Not resolved');
}).catch((result)=>{
console.log('p4 reject: ', result);
})