Skip to content

Instantly share code, notes, and snippets.

@potch
Last active February 28, 2017 19:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save potch/38944904d8a90a0d22ac24514cbd17fd to your computer and use it in GitHub Desktop.
Save potch/38944904d8a90a0d22ac24514cbd17fd to your computer and use it in GitHub Desktop.
<p>Firefox 52 also includes a brand new JavaScript feature from ES2017: asynchronous functions and their companion, the <code>await</code> keyword. Async functions build on top of ES2015 Promises, allowing authors to write asynchronous sequences in a similar way to how they would write their synchronous equivalents.</p>
<p>Take the following example, which takes the result of one asynchronous request, modifies it, and passes it as the argument to a second asynchronous function. Here&#39;s how it would look with a traditional callback approach:</p>
<pre><code class="language-javascript">function doThings() {
doThingA(function (err, result) {
if (err) {
handleError(err);
} else {
doThingB(result + 1, function (err, newResult) {
if (err) {
handleError(err)
} else {
useResult(newResult);
}
});
}
});
}</code></pre>
<p>Relatively straightforward, but if we were to need to do additional processing and asynchronous requests, the levels of nesting or series of callback functions could become difficult to manage. Also, with more complex callback sequences, it can become difficult to determine the flow of the code, making debugging difficult.</p>
<p>Promises, introduced in ES105, allow for a more compact representation of the same flow:</p>
<pre><code class="language-javascript">function doThings() {
doThingA()
.then(function (result) {
return doThingB(result + 1);
})
.then(useResult)
.catch(handleError);
}</code></pre><
<p>Promises excel at simplifying these sequential method sequences. In this example, instead of passing a function to <code>doThingA</code> and <code>doThingB</code>, the functions now return a Promise, which will be resolved when the function&#39;s result is availasble. However, when additional processing or conditional calls are required, the nesting can still become quite deep and control flow can again be hard to follow.</p>
<p>Async functions allow us to re-write the example to resemble the way we would write a synchronous equivalent:</p>
<pre><code class="language-javascript">async function doThings() {
try {
let result = await doThingA();
useResult(await doThingB(result + 1));
} catch (err) {
handleError(err);
}
}</code></pre>
<p>The <code>async</code> keyword in front of the function tells the JS engine that the following function can be paused by asynchronous requests, and that the result of the function will be a Promise. Each time we need to wait for an asynchronous result, we use the <code>await</code> keyword. This will pause execution of the function <em>without stopping other functions from running</em>. Also, <code>doThingA</code> and <code>doThingB</code> don&#39;t need to be changed from how they would be written in the Promise example. </p>
<p>Async functions aren&#39;t a cure-all for complex control flow, but for many cases can simplifty the authoring and maintenance of async code, without importing costly libraries.</p>

Firefox 52 also includes a brand new JavaScript feature from ES2017: asynchronous functions and their companion, the await keyword. Async functions build on top of ES2015 Promises, allowing authors to write asynchronous sequences in a similar way to how they would write their synchronous equivalents.

Take the following example, which takes the result of one asynchronous request, modifies it, and passes it as the argument to a second asynchronous function. Here's how it would look with a traditional callback approach:

function doThings() {
  doThingA(function (err, result) {
    if (err) {
      handleError(err);
    } else {
      doThingB(result + 1, function (err, newResult) {
        if (err) {
          handleError(err)
        } else {      
          useResult(newResult);
        }
      });      
    }
  });
}

Relatively straightforward, but if we were to need to do additional processing and asynchronous requests, the levels of nesting or series of callback functions could become difficult to manage. Also, with more complex callback sequences, it can become difficult to determine the flow of the code, making debugging difficult.

Promises, introduced in ES105, allow for a more compact representation of the same flow:

function doThings() {
  doThingA()
    .then(function (result) {
      return doThingB(result + 1);
    })
    .then(useResult)
    .catch(handleError);
}

Promises excel at simplifying these sequential method sequences. In this example, instead of passing a function to doThingA and doThingB, the functions now return a Promise, which will be resolved when the function's result is availasble. However, when additional processing or conditional calls are required, the nesting can still become quite deep and control flow can again be hard to follow.

Async functions allow us to re-write the example to resemble the way we would write a synchronous equivalent:

async function doThings() {
  try {
    let result = await doThingA();
    useResult(await doThingB(result + 1));    
  } catch (err) {
    handleError(err);
  }
}

The async keyword in front of the function tells the JS engine that the following function can be paused by asynchronous requests, and that the result of the function will be a Promise. Each time we need to wait for an asynchronous result, we use the await keyword. This will pause execution of the function without stopping other functions from running. Also, doThingA and doThingB don't need to be changed from how they would be written in the Promise example.

Async functions aren't a cure-all for complex control flow, but for many cases can simplifty the authoring and maintenance of async code, without importing costly libraries.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment