## 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); ```