Upgrade to Pro — share decks privately, control downloads, hide ads and more …

LDNWebPerf December 2016 - Ingvar Stepanyan

LDNWebPerf December 2016 - Ingvar Stepanyan

London Web Performance Group

December 06, 2016
Tweet

More Decks by London Web Performance Group

Other Decks in Technology

Transcript

  1. Abusing ES6+ features
    for nicer parallelism
    * Disclaimer: no people, animals or JS features were harmed during the talk
    Ingvar Stepanyan aka @RReverser

    View Slide

  2. Calculation in the main thread
    // get inputs
    var x = document.getElementById("x").value;
    var y = document.getElementById("y").value;
    // VERY useful calculations
    for (var end = Date.now() + 3000; Date.now() < end; );
    var result = x * y;
    // output result
    document.getElementById("output").value = result;
    jsbin

    View Slide

  3. Parallelism looks cool

    View Slide

  4. …but implementations might hurt

    View Slide

  5. Web Workers: client (main thread)
    var worker = new Worker("worker.js");
    worker.addEventListener("message", function (event) {
    // output result
    document.getElementById("output").value = event.data.result;
    });
    // get inputs
    var x = document.getElementById("x").value;
    var y = document.getElementById("y").value;
    worker.postMessage({ x: x, y: y });

    View Slide

  6. Web Workers: server (worker)
    self.addEventListener("message", function (event) {
    // get inputs
    var x = event.data.x;
    var y = event.data.y;
    // VERY useful calculations
    for (var end = Date.now() + 3000; Date.now() < end; );
    var result = x * y;
    postMessage({ result: result });
    });

    View Slide

  7. Web Workers: client (main thread)
    var worker = new Worker("worker.js"), inc = 0;
    // get inputs
    var id = inc++;
    var x = document.getElementById("x").value;
    var y = document.getElementById("y").value;
    worker.addEventListener("message", function handler(event) {
    if (event.data.id === id) {
    this.removeEventListener("message", handler);
    // output result
    document.getElementById("output").value = event.data.result;
    }
    });
    worker.postMessage({ id: id, x: x, y: y });

    View Slide

  8. Web Workers: server (worker)
    self.addEventListener("message", function (event) {
    // get inputs
    var id = event.data.id;
    var x = event.data.x;
    var y = event.data.y;
    // VERY useful calculations
    for (var end = Date.now() + 3000; Date.now() < end; );
    var result = x * y;
    postMessage({ id: id, result: result });
    });
    jsbin

    View Slide

  9. Calculation in the main thread
    // get inputs
    var x = document.getElementById("x").value;
    var y = document.getElementById("y").value;
    // VERY useful calculations
    for (var end = Date.now() + 3000; Date.now() < end; );
    var result = x * y;
    // output result
    document.getElementById("output").value = result;

    View Slide

  10. Web Workers
    //// index.js ////

    var worker = new Worker("worker.js"), inc = 0;
    // get inputs
    var id = inc++;
    var x = document.getElementById("x").value;
    var y = document.getElementById("y").value;
    worker.addEventListener("message", function
    handler(event) {
    if (event.data.id === id) {
    this.removeEventListener("message", handler);
    // output result
    document.getElementById("output").value =
    event.data.result;
    }
    });
    worker.postMessage({ id: id, x: x, y: y });
    //// worker.js ////

    self.addEventListener("message", function (event) {
    // get inputs
    var id = event.data.id;
    var x = event.data.x;
    var y = event.data.y;
    // VERY useful calculations
    for (var end = Date.now() + 3000; Date.now() <
    end;);
    var result = x * y;
    postMessage({ id: id, result: result });
    });

    View Slide

  11. View Slide

  12. Calculation in the main thread
    // get inputs
    var x = document.getElementById("x").value;
    var y = document.getElementById("y").value;
    // VERY useful calculations
    for (var end = Date.now() + 3000; Date.now() < end; );
    var result = x * y;
    // output result
    document.getElementById("output").value = result;

    View Slide

  13. Dream API
    parallel(function () {
    // get inputs
    var x = document.getElementById("x").value;
    var y = document.getElementById("y").value;
    // VERY useful calculations
    for (var end = Date.now() + 3000; Date.now() < end;);
    var result = x * y;
    // output result
    document.getElementById("output").value = result;
    });

    View Slide

  14. Let’s mix some stuff

    View Slide

  15. ES6: Promise API
    doSomethingAsync().then(
    function onSuccess(result) {},
    function onError(error) {}
    )
    // or just:
    return doSomethingAsync().then(function (result) {
    // do something with result
    })

    View Slide

  16. ES6: Promise API
    $.ajax(url).then(function (data) {
    $('#result').html(data);
    var status = $('#status').html('Download complete.');
    return status.fadeIn().promise().then(function () {
    return sleep(2000);
    }).then(function () {
    return status.fadeOut();
    });
    });

    View Slide

  17. ES6: Promise API
    $.ajax(url).then(data => {
    $('#result').html(data);
    var status = $('#status').html('Download complete.');
    return (
    status.fadeIn().promise()
    .then(() => sleep(2000))
    .then(() => status.fadeOut())
    );
    });

    View Slide

  18. ES8: async/await
    var data = await $.ajax(url);
    $('#result').html(data);
    var status = $('#status').html('Download complete.');
    await status.fadeIn.promise();
    await sleep(2000);
    await status.fadeOut();

    View Slide

  19. ES8: async/await
    var expr = await promise;

    nextStatement();
    var expr;
    promise.then(result => {
    expr = result;
    nextStatement();
    });

    View Slide

  20. ES8: async/await
    console.log('Hello');
    await { then: resolve => setTimeout(resolve, 3000) };
    console.log('world');

    View Slide

  21. ES6: Proxy API
    var proxy = new Proxy({}, {
    get(target, name) {
    return name;
    },
    set(target, name, value) {
    console.log(name, '=', value);
    },
    // ...
    });
    proxy.a; // 'a'
    proxy[0]; // '0'
    proxy.a = 1; // console: 'a = 1'
    proxy.b = 2; // console: 'b = 2'

    View Slide

  22. ES6: Proxy API
    var proxy = new Proxy({}, {
    get(target, name) {
    if (name === 'then') {
    return resolve => resolve(target.name);
    }
    return new Proxy({ name }, this);
    }
    });
    proxy.a.then(console.log); // 'a'
    proxy.a.b.c.then(console.log); // 'c'
    proxy[0].then(console.log); // '0'

    View Slide

  23. Let’s mix!
    var proxy = new Proxy({}, {
    get(target, name) {
    if (name === 'then') {
    return resolve => resolve(target.name);
    }
    return new Proxy({ name }, this);
    }
    });
    console.log(await proxy.a); // ‘a'
    console.log(await proxy.a.b.c); // 'c'
    console.log(await proxy[0]); // '0'

    View Slide

  24. Let’s mix!
    var proxy = new Proxy({}, {
    get(target, name) {
    var chain = { type: 'get', target, name };
    if (name === 'then') {
    return askMainThread(chain);
    }
    return new Proxy(chain, this);
    }
    });
    proxy.a; // {type: 'get', target: {}, name: 'a'}
    proxy.a.b; // {type: 'get', target: {…, name: 'a'}, name: 'b'}
    await proxy.a.b.c; // 'a.b.c'

    View Slide

  25. ES6: Proxy API
    await proxy.document.getElementById('x').value
    // into:
    askMainThread({
    type: 'get',
    target: {
    type: 'call',
    target: {
    type: 'get',
    target: { type: 'get', target: {}, name: 'document' },
    name: 'getElementById'
    },
    args: ['x']
    },
    name: 'value'
    })(resolve => …, reject => …)

    View Slide

  26. ES8-powered API
    parallel(async function (proxy) {
    // get inputs
    var x = await proxy.document.getElementById("x").value;
    var y = await proxy.document.getElementById("y").value;
    // VERY useful calculations
    for (var end = Date.now() + 3000; Date.now() < end;);
    var result = x * y;
    // output result
    proxy.document.getElementById("output").value = result;
    });

    View Slide

  27. ES8-powered API (just like we wanted!)
    parallel(async function ({ document }) {
    // get inputs
    var x = await document.getElementById("x").value;
    var y = await document.getElementById("y").value;
    // VERY useful calculations
    for (var end = Date.now() + 3000; Date.now() < end;);
    var result = x * y;
    // output result
    document.getElementById("output").value = result;
    });

    View Slide

  28. Thanks!

    View Slide