We closed our conversation on callbacks by highlighting one of the issues of callbacks - nesting. It's easy to find yourself nested 3-4 layers deep in even the simplest of applications. This makes code maintenance and debugging a challenge. Enter promises.
Promises build on the concept of callbacks - they both guarantee your code will be called when the operation is complete. The difference between the two is with a promise you're effectively handed an IOU. The method you're calling promises it will call your code when the operation is complete.
One important thing to note about promises is they are relatively new in JavaScript. There still exists a fair amount of legacy code that only supports callbacks. That said, you'll notice most of the libraries you'll commonly use will support promises.
Let's take another look at the get
function in jQuery. Previously, we had a sample that used a callback:
// callback
$.get('http://www.example.com', (data) => {
console.log(data);
});
In the above example, once the call successfully completes, our delegate is executed, and the data would be printed to the screen. We can rewrite this using a promise by doing the following:
// basic promise
$.get('http://www.example.com')
.then((data) => {
console.log(data);
});
By using then
, we pass in the function we want called once get
completes.
If you look at the example above, you might be wondering why we'd bother using a promise here. After all, there's only one level of nesting. The real power comes when we're making multiple calls. We might be using Mongoose, and then making some external call. You'll notice in that situation, we can string one promise call after another, after another...
// stringing together promises
SomeModel.findById(42)
.then((result) => {
executeServerCall(result); // returns a promise
})
.then((result) => {
console.log(`The server returned a result`);
console.log(result);
});
Assuming that executeServerCall
returns a promise, the second then
allows us to specify the function we want executed when it completes successfully. By using promises, we wind up with more readable code, and code that flows better than callbacks. We're basically saying "Do this, then do this, then do this, then ..." And that's not even mentioning avoiding the variable scoping issues that can arise when using nested callbacks.
then
actually takes two parameters. The first, which we've used, is what happens if something goes wrong. The second is to catch any error. We can use them both as follows:
$.get('http://www.example.com')
.then((data) => {
console.log('Success!!');
console.log(data);
}, (error) => {
console.log('Something went wrong :-(');
console.log(error);
});
At the end of the day, there is no logical difference between callbacks and promises; they both do the same thing. Promises allow for cleaner syntax, and are easier to maintain. You'll notice most developers these days use promises.