|
| 1 | +First note, - **Await works only with Promises, it does not work with callbacks. So to implement async-await to a function/code, I first have to convert the callback to a Promise ** |
| 2 | + |
| 3 | +Fist let's take the simplest of example. `setTimeout` is a straightforward browser API that waits for a specified period of time and then executes a callback. A standard use looks like this: |
| 4 | + |
| 5 | +```js |
| 6 | +function doStuff() { |
| 7 | + /_..._/; |
| 8 | +} |
| 9 | + |
| 10 | +setTimeout(doStuff, 300); |
| 11 | +``` |
| 12 | + |
| 13 | +A Promise-based API for this function would likely look something like this code. |
| 14 | + |
| 15 | +`timeout(300).then(doStuff)` |
| 16 | + |
| 17 | +We can create an API like that using setTimeout. To do that, we’ll need a function timeout which takes a timeout variable and returns a Promise. |
| 18 | + |
| 19 | +You can define A+ compliant Promises using the Promise constructor, which expects a single function as an argument. That function takes 2 arguments, a resolve function and a reject function. The wonderful thing is that under the covers these are just callback functions that the Promise api glosses over. |
| 20 | + |
| 21 | +```js |
| 22 | +function timeout(delay) { |
| 23 | + return new Promise(function(resolve, reject) { |
| 24 | + setTimeout(resolve, delay); |
| 25 | + }); |
| 26 | +} |
| 27 | +``` |
| 28 | + |
| 29 | +We don’t use the reject callback, since setTimeout doesn’t provide any hooks for an error state. So we pass resolve as the callback to setTimeout, and that is all we need. Now we have a great chainable setTimeout function that we could include in a Promise chain. |
| 30 | + |
| 31 | +##### Now lets do a slightly more complicated version of the same exercise |
| 32 | + |
| 33 | +[Source Code](https://github.com/coreyc/converting-callbacks/blob/master/index.js) |
| 34 | + |
| 35 | +#### Callback version |
| 36 | + |
| 37 | +```js |
| 38 | +const callbackFn = (firstName, callback) => { |
| 39 | + setTimeout(() => { |
| 40 | + if (!firstName) return callback(new Error("no first name passed in!")); |
| 41 | + |
| 42 | + const fullName = `${firstName} Doe`; |
| 43 | + |
| 44 | + return callback(fullName); |
| 45 | + }, 2000); |
| 46 | +}; |
| 47 | + |
| 48 | +callbackFn("John", console.log); |
| 49 | +callbackFn(null, console.log); |
| 50 | +``` |
| 51 | + |
| 52 | +We're using the setTimeout() function in order to make our function asynchronous. In addition to setTimeout(), other asynchronous operations you're likely to see in the real-world are: AJAX and HTTP calls, database calls, filesystem calls (in the case of Node, if no synchronous version exists), etc. |
| 53 | + |
| 54 | +In this function, we "reject" it if the first name argument is null. When we do pass in the firstName argument, the callback function (almost always the last argument in a callback-based function's argument list) gets called and returns our value after the 2 seconds set in setTimeout(). |
| 55 | + |
| 56 | +#### Promise version - And here's the Promise-based version of that function: |
| 57 | + |
| 58 | +```js |
| 59 | +const promiseFn = firstName => { |
| 60 | + return new Promise((resolve, reject) => { |
| 61 | + setTimeout(() => { |
| 62 | + if (!firstName) reject(new Error("no first name passed in!")); |
| 63 | + |
| 64 | + const fullName = `${firstName} Doe`; |
| 65 | + |
| 66 | + resolve(fullName); |
| 67 | + }, 2000); |
| 68 | + }); |
| 69 | +}; |
| 70 | + |
| 71 | +promiseFn("Jane").then(console.log); |
| 72 | +promiseFn().catch(console.log); |
| 73 | +``` |
| 74 | + |
| 75 | +Converting to a Promise-based function is actually pretty simple. Look at the below diagram for a visual explanation: |
| 76 | + |
| 77 | +<img src="convert-callback-to-promise-async-await-1.png"> |
| 78 | + |
| 79 | +#### Further reading |
| 80 | + |
| 81 | +1> https://benmccormick.org/2015/12/30/es6-patterns-converting-callbacks-to-promises |
| 82 | + |
| 83 | +2> https://dev.to/ccleary00/how-to-rewrite-a-callback-function-in-promise-form-and-asyncawait-form-in-javascript-410e |
0 commit comments