<!-- 
markdown-to-slides async.md -o async.html
-->

## Event-Based

* Javascript is single-threaded (like every sane GUI)

* no mutexes, no data-races

* browser main loop (hidden)

### Callbacks

```javascript
setTimeout(function onTimeout() { ... }, 10000);
setTimeout(() => { ... }, 10000);  // ES6 arrow function
```
    
---
## Promises

```javascript
$http.get('/api/user').then(onSuccess).catch(onError);

function onSuccess(resp) {
    var url = '/api/user/' + resp.data.id + '/info';
    return $http.get(url).then(infoSuccess);

    function infoSuccess(resp) {
        console.log(resp.data.user_info);
    }
}

function onError(reason) {
    // show `reason` to user / redirect to login
}
```

#### ES6 Promises

Compatibility: any object with .then()

* Promise.resolve(value | promise) (replaces $q.when())
* Promise.reject(reason)
* Promise.all(iterable)

---
## Promise Hell

WebDriverJS using google:

```javascript
let driver = new Builder().forBrowser('firefox').build();
driver.get('http://www.google.com/ncr')
  .then(_ => driver.findElement(By.name('q')))
  .then(q => q.sendKeys('webdriver'))
  .then(_ => driver.findElement(By.name('btnG')))
  .then(btnG => btnG.click())
  .then(_ => driver.wait(until.titleIs('webdriver - Google Search')
                         1000))
  .then(_ => driver.quit(), e => {
    console.error(e);
    driver.quit();
  });
```
      
* Source: https://github.com/SeleniumHQ/selenium/issues/2969
* You don't actually write this. (Promise Manager / Control Flow)

---
## async / await syntax

Protractor e2e test:

```javascript
it('should wait ...', async function() {
  const usernameInput = element(...);
  const name = element(...);

  await browser.get('index.html#/form');

  await expect(name.getText()).toEqual('Anon');

  await usernameInput.clear();
  await usernameInput.sendKeys('Jane');
  await expect(name.getText()).toEqual('Jane');
});
```

### Advantages

Compared to old Control Flow:

* can actually set breakpoints
* better stack traces
* exception handling: try/catch (vs .catch(), onError)

---
## Puppeteer Example

```javascript
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.screenshot({path: 'example.png'});

  browser.close();
})();
```

### Parsing Cheat-Sheet
* async is a keyword, not a name
* arrow function
* immediately invoked (IFFE)

---
## ECMAScript

* ES5 (2009): "Internet Explorer"

* ES6 (2015): promises, arrow functions, generators (function*)

* ES7 (2016): -

* ES8 (2017): await/async

http://caniuse.com/#search=await (Node 7 and Node 8 (LTS))

## Libraries

* kriskowal/q (and Angular's $q) - Promises

* caolan/async, asyncawait, bluebird, etc. etc.

* babel can convert ES8 async function to FSM

---
## Callback Hell (Part II)

"Unlike Callback Hell, Promise Hell is self inflicted."

```javascript
fetchBook()
  .then((book) => {
    return formatBook(book)
      .then((book) => {
        return sendBookToPrinter(book);
      });
  });
```
  
Can rewrite as:

```javascript
fetchBook()
.then(formatBook)
.then(sendBookToPrinter);
```
  
