$30 off During Our Annual Pro Sale. View Details »

Fluent Conf: Rise of Async JavaScript

Fluent Conf: Rise of Async JavaScript

Jeremy Fairbank

March 09, 2016
Tweet

More Decks by Jeremy Fairbank

Other Decks in Programming

Transcript

  1. the RISEof async…
    JavaScript
    Jeremy Fairbank
    blog.jeremyfairbank.com
    @elpapapollo | gh/jfairbank

    View Slide

  2. We help brands excel.
    pushagency.io
    Your website, SimplyBuilt.
    simplybuilt.com

    View Slide

  3. View Slide

  4. View Slide

  5. View Slide

  6. View Slide

  7. “Call me maybe?”

    View Slide

  8. Async API
    Callback

    View Slide

  9. Callback
    fetchUserById(1, function(err, user) {
    if (err) {
    console.error('Could not retrieve user');
    } else {
    console.log(user);
    }
    });

    View Slide

  10. });
    });
    });
    });
    });
    });
    Callback
    Callback
    Callback
    Callback
    Callback
    Callback

    View Slide

  11. function fetchCustomerNameForOrder(orderId, done, fail) {
    fetchOrder(orderId, function(err, order) {
    if (err) {
    logError(err);
    fail(err);
    } else {
    fetchCustomer(
    order.customerId,
    function(err, customer) {
    if (err) {
    logError(err);
    fail(err);
    } else {
    done(customer.name);
    }
    }
    );
    }
    });
    }

    View Slide

  12. function fetchCustomerNameForOrder(orderId, done, fail) {
    fetchOrder(orderId, function(err, order) {
    if (err) {
    logError(err);
    fail(err);
    } else {
    fetchCustomer(
    order.customerId,
    function(err, customer) {
    if (err) {
    logError(err);
    fail(err);
    } else {
    done(customer.name);
    }
    }
    );
    }
    });
    }

    View Slide

  13. function fetchCustomerNameForOrder(orderId, done, fail) {
    fetchOrder(orderId, function(err, order) {
    if (err) {
    logError(err);
    fail(err);
    } else {
    fetchCustomer(
    order.customerId,
    function(err, customer) {
    if (err) {
    logError(err);
    fail(err);
    } else {
    done(customer.name);
    }
    }
    );
    }
    });
    }

    View Slide

  14. Async API ?

    View Slide

  15. Promise
    function fetchCustomerNameForOrder(orderId) {
    return fetchOrder(orderId)
    .then(order => fetchCustomer(order.customerId))
    .then(customer => customer.name);
    }

    View Slide

  16. .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)
    .then(...)

    View Slide

  17. Error
    Error
    Error
    Error

    View Slide

  18. function fetchCustomerNameForOrder(orderId) {
    return fetchOrder(orderId)
    .then(order => fetchCustomer(order.customerId))
    .then(customer => customer.name)
    .catch(err => {
    logError(err);
    throw err;
    });
    }

    View Slide

  19. Getting there…

    View Slide

  20. • Readable, synchronous
    program flow
    • Nonblocking
    • Use native flow control
    constructs

    View Slide

  21. async function fetchCustomerNameForOrder(orderId) {
    try {
    const order = await fetchOrder(orderId);
    const customer = await fetchCustomer(order.customerId);
    return customer.name;
    } catch (err) {
    logError(err);
    throw err;
    }
    }

    View Slide

  22. async function fetchCustomerNameForOrder(orderId) {
    try {
    const order = await fetchOrder(orderId);
    const customer = await fetchCustomer(order.customerId);
    return customer.name;
    } catch (err) {
    logError(err);
    throw err;
    }
    }

    View Slide

  23. async function fetchCustomerNameForOrder(orderId) {
    try {
    const order = await fetchOrder(orderId);
    const customer = await fetchCustomer(order.customerId);
    return customer.name;
    } catch (err) {
    logError(err);
    throw err;
    }
    }

    View Slide

  24. async function fetchCustomerNameForOrder(orderId) {
    try {
    const order = await fetchOrder(orderId);
    const customer = await fetchCustomer(order.customerId);
    return customer.name;
    } catch (err) {
    logError(err);
    throw err;
    }
    }

    View Slide

  25. View Slide

  26. Await

    View Slide

  27. function fetchOrder(orderId) {
    return fetch(`/orders/${orderId}`)
    .then(response => response.json());
    }
    function printOrder(orderId) {
    fetchOrder(orderId)
    .then(order => console.log(order));
    }

    View Slide

  28. function fetchOrder(orderId) {
    return fetch(`/orders/${orderId}`)
    .then(response => response.json());
    }
    async function printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }

    View Slide

  29. async printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }
    fetchOrder(orderId) order

    View Slide

  30. async printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }
    await

    View Slide

  31. async printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }
    await order

    View Slide

  32. await order

    View Slide

  33. await order

    View Slide

  34. async printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    } ?

    View Slide

  35. async function printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }
    printOrder(1);
    Invoke

    View Slide

  36. async function printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }
    printOrder(1);
    Encounter await

    View Slide

  37. async function printOrder(orderId) {
    const order = await fetchOrder(orderId);
    console.log(order);
    }
    printOrder(1);
    Wrap in Promise.resolve

    View Slide

  38. Wrap in Promise.resolve
    async function printOrder(orderId) {
    const promise = Promise.resolve(fetchOrder(orderId));
    console.log(order);
    }
    printOrder(1);

    View Slide

  39. async function printOrder(orderId) {
    const promise = Promise.resolve(fetchOrder(orderId));
    console.log(order);
    }
    printOrder(1);
    Wrap rest with then callback

    View Slide

  40. async function printOrder(orderId) {
    const promise = Promise.resolve(fetchOrder(orderId));
    return promise.then(order => {
    console.log(order);
    return Promise.resolve(undefined);
    });
    }
    printOrder(1);
    Wrap rest with then callback

    View Slide

  41. async function printOrder(orderId) {
    const promise = Promise.resolve(fetchOrder(orderId));
    return promise.then(order => {
    console.log(order);
    return Promise.resolve(undefined);
    });
    }
    printOrder(1);
    Wrap implicit return with
    Promise.resolve

    View Slide

  42. function fetchCustomerNameForOrder(orderId) {
    return Promise.resolve(fetchOrder(orderId))
    .then(order => {
    return Promise.resolve(fetchCustomer(order.customerId))
    .then(customer => {
    return Promise.resolve(customer.name);
    });
    });
    }
    ?

    View Slide

  43. async function meaningOfLife() {
    return 42;
    }
    meaningOfLife() === 42;
    ???

    View Slide

  44. async function meaningOfLife() {
    return 42;
    }
    function meaningOfLife() {
    return Promise.resolve(42);
    }
    meaningOfLife()
    .then(answer => answer === 42);

    View Slide

  45. Exceptional
    Situations

    View Slide

  46. async function printOrder(orderId) {
    try {
    const order = await fetchOrder(orderId);
    console.log(order);
    } catch (e) {
    console.log('Error retrieving order', e);
    }
    }

    View Slide

  47. async function printOrder(orderId) {
    try {
    const order = await fetchOrder(orderId);
    console.log(order);
    } catch (e) {
    console.log('Error retrieving order', e);
    }
    } ?

    View Slide

  48. function fetchOrder(orderId) {
    return fetch(`/orders/${orderId}`)
    .then(resp => {
    if (resp.status === 404) {
    throw new Error('Order not found');
    }
    return resp.json();
    });
    }

    View Slide

  49. function fetchOrder(orderId) {
    return new Promise((resolve, reject) => {
    $.get(`/orders/${orderId}`)
    .done(order => resolve(order))
    .fail(resp => {
    if (resp.status === 404) {
    reject(new Error('Order not found'));
    }
    });
    });
    }

    View Slide

  50. Error
    Error
    Error
    Error

    View Slide

  51. Regain Control

    View Slide

  52. async function findOrCreateOrder(orderId) {
    let order;
    if (await orderExists(orderId)) {
    order = await fetchOrder(orderId);
    } else {
    order = await createOrder();
    }
    return order;
    }

    View Slide

  53. async function findOrCreateOrder(orderId) {
    let order;
    if (await orderExists(orderId)) {
    order = await fetchOrder(orderId);
    } else {
    order = await createOrder();
    }
    return order;
    }

    View Slide

  54. async function printOrders(orderIds) {
    for (const id of orderIds) {
    const order = await fetchOrder(id);
    console.log(order);
    }
    }

    View Slide

  55. async function printOrders(orderIds) {
    for (const id of orderIds) {
    const order = await fetchOrder(id);
    console.log(order);
    }
    }

    View Slide

  56. async function printOrders(orderIds) {
    for (const id of orderIds) {
    const order = await fetchOrder(id);
    console.log(order);
    }
    } Problem?

    View Slide

  57. async function printOrders(orderIds) {
    for (const id of orderIds) {
    const order = await fetchOrder(id);
    console.log(order);
    }
    }
    printOrders([1, 2, 3]);

    View Slide

  58. printOrders([1, 2, 3]);
    await fetchOrder(1);
    await fetchOrder(2);
    await fetchOrder(3);

    View Slide

  59. printOrders([1, 2, 3]);
    await fetchOrder(1);
    await fetchOrder(2);
    await fetchOrder(3);

    View Slide

  60. printOrders([1, 2, 3]);
    await fetchOrder(1);
    await fetchOrder(2);
    await fetchOrder(3);

    View Slide

  61. async function printOrders(orderIds) {
    const orders = await Promise.all(
    orderIds.map(fetchOrder)
    );
    orders.forEach(order => console.log(order));
    }

    View Slide

  62. async function printOrders(orderIds) {
    const orders = await Promise.all(
    orderIds.map(fetchOrder)
    );
    orders.forEach(order => console.log(order));
    }

    View Slide

  63. printOrders([1, 2, 3]);
    await Promise.all([
    fetchOrder(1),
    fetchOrder(2),
    fetchOrder(3)
    ]);

    View Slide

  64. printOrders([1, 2, 3]);
    Demo
    rise.of.async.jeremyfairbank.com

    View Slide

  65. View Slide

  66. $ npm install --save-dev \
    babel-core \
    babel-cli \
    babel-preset-es2015 \
    babel-plugin-syntax-async-functions \
    babel-plugin-transform-regenerator \
    babel-plugin-transform-runtime

    View Slide

  67. .babelrc
    {
    "presets": ["es2015"],
    "plugins": [
    "syntax-async-functions",
    "transform-regenerator",
    "transform-runtime"
    ]
    }

    View Slide

  68. $ node_modules/.bin/babel-node myAsyncFile.js

    View Slide

  69. • tc39.github.io/ecmascript-asyncawait/
    • github.com/tc39/ecmascript-asyncawait
    • github.com/tc39/ecma262
    Resources

    View Slide

  70. THANKS!
    Jeremy Fairbank
    blog.jeremyfairbank.com
    @elpapapollo | gh/jfairbank
    speakerdeck.com/jfairbank/fluent-conf-rise-of-async-javascript
    SLIDES:
    github.com/jfairbank/rise-of-async-js-talk
    CODE:

    View Slide