SlideShare a Scribd company logo
ES.next for humans
@janjongboom
LvivJS 2014
@janjongboom
@janjongboom
ESNext for humans - LvivJS 16 August 2014
I hate
JavaScript!
ESNext for humans - LvivJS 16 August 2014
VBScript
<3 <3 <3
ESNext for humans - LvivJS 16 August 2014
ESNext for humans - LvivJS 16 August 2014
програма
Things you could already do
Things you needed a framework for
Things that were impossible
Things you can already do
alt: S*#t that annoys Jan in JavaScript
NodeList is not an array
1 document.querySelectorAll('li')
2 .filter(function(li) {
3 /* do something */
4 });
5
ERROR: document.querySelectorAll(...).filter
is not a function
NodeList is not an array
1 Array.prototype.slice.call(
2 document.querySelectorAll('li')
3 )
NodeList is not an array
1 Array.prototype.slice.call(
2 document.querySelectorAll('li')
3 )
1 Array.from(
2 document.querySelectorAll('li')
3 )
Variable scoping
1 var a = 7;
2
3 if (something) {
4 var a = 9;
5 doSomethingElse(a);
6 }
7
8 console.log(a);
Variable scoping
1 var a = 7;
2
3 if (something) {
4 var a = 9;
5 doSomethingElse(a);
6 }
7
8 console.log(a);
// can be 7 or 9 depending on 'something'
Variable scoping
1 var a = 7;
2
3 if (something) {
4 var a = 9;
5 doSomethingElse(a);
6 }
7
8 console.log(a);
// can be 7 or 9 depending on 'something'
Variable scoping
1 var a = 7;
2
3 if (something) {
4 var a = 9;
5 doSomethingElse(a);
6 }
7
8 console.log(a);
// can be 7 or 9 depending on 'something'
Variable scoping
1 let a = 7;
2
3 if (something) {
4 let a = 9;
5 doSomethingElse(a);
6 }
7
8 console.log(a);
// always 7
‘let’ to the rescue
Variable scoping
1 let a = 7;
2
3 if (something) {
4 let a = 9;
5 doSomethingElse(a);
6 }
7
8 console.log(a);
// always 7
‘let’ to the rescue
Tuples
Multiple return values
1 function getPosition() {
2 return [ 12, 91 ];
3 }
4
5 var pos = getPosition();
6 var x = pos[0],
7 y = pos[1];
8
9 function getPosition() {
10 return { x: 12, y: 91 };
11 }
12
13 var pos = getPosition();
14 var x = pos.x;
15 y = pos.y;
1 function getPosition() {
2 return [ 12, 91 ];
3 }
4
5 var pos = getPosition();
6 var x = pos[0],
7 y = pos[1];
8
9 function getPosition() {
10 return { x: 12, y: 91 };
11 }
12
13 var pos = getPosition();
14 var x = pos.x;
15 y = pos.y;
let [x, y] = getPosition();
1 function getPosition() {
2 return [ 12, 91 ];
3 }
4
5 var pos = getPosition();
6 var x = pos[0],
7 y = pos[1];
8
9 function getPosition() {
10 return { x: 12, y: 91 };
11 }
12
13 var pos = getPosition();
14 var x = pos.x;
15 y = pos.y;
let [x, y] = getPosition();
let {x, y} = getPosition();
1 var data = {};
2
3 data['jan'] = 'awesome';
4 data['pete'] = 'not so awesome';
5
6 var ele1 = document.querySelector('#el1');
7 data[ele1] = 'first element';
8
9 var ele2 = document.querySelector('#el2');
10 data[ele2] = 'second element';
11
12 console.log(data[ele1]);
Maps
1 var data = {};
2
3 data['jan'] = 'awesome';
4 data['pete'] = 'not so awesome';
5
6 var ele1 = document.querySelector('#el1');
7 data[ele1] = 'first element';
8
9 var ele2 = document.querySelector('#el2');
10 data[ele2] = 'second element';
11
12 console.log(data[ele1]);
Maps
1 var data = {};
2
3 data['jan'] = 'awesome';
4 data['pete'] = 'not so awesome';
5
6 var ele1 = document.querySelector('#el1');
7 data[ele1] = 'first element';
8
9 var ele2 = document.querySelector('#el2');
10 data[ele2] = 'second element';
11
12 console.log(data[ele1]);
Maps
“second element”
1 var data = {};
2
3 data['jan'] = 'awesome';
4 data['pete'] = 'not so awesome';
5
6 var ele1 = document.querySelector('#el1');
7 data[ele1] = 'first element';
8
9 var ele2 = document.querySelector('#el2');
10 data[ele2] = 'second element';
11
12 console.log(data[ele1]);
Maps
Maps
1 var data = {};
2
3 data['jan'] = 'awesome';
4 data['pete'] = 'not so awesome';
5
6 var ele1 = document.querySelector('#el1');
7 data[ele1] = 'first element';
8
9 var ele2 = document.querySelector('#el2');
10 data[ele2] = 'second element';
11
12 console.log(data[ele1]);
Maps
1 var data = {};
2
3 data['jan'] = 'awesome';
4 data['pete'] = 'not so awesome';
5
6 var ele1 = document.querySelector('#el1');
7 data[ele1] = 'first element';
8
9 var ele2 = document.querySelector('#el2');
10 data[ele2] = 'second element';
11
12 console.log(data[ele1]);
data[ele2.toString()]
ele2.toString() =>
“[object HTMLDivElement”]
Maps
1 var data = new Map();
2
3 data.set('jan', 'awesome');
4
5 data.has('jan'); // true
6 data.get('jan'); // "awesome"
7
8 var ele1 = document.querySelector('#el1');
9 data.set(ele1, 'first element');
10
11 var ele2 = document.querySelector('#el2');
12 data.set(ele2, 'second element');
13
14 console.log(data.get(ele1)); // "first element"
Maps
1 var data = new Map();
2
3 data.set('jan', 'awesome');
4
5 data.has('jan'); // true
6 data.get('jan'); // "awesome"
7
8 var ele1 = document.querySelector('#el1');
9 data.set(ele1, 'first element');
10
11 var ele2 = document.querySelector('#el2');
12 data.set(ele2, 'second element');
13
14 console.log(data.get(ele1)); // "first element"
Function boilerplate
1
2 someArray
3 .filter(function(item) {
4 return item.isActive;
5 })
6 .map(function(item) {
7 return item.id;
8 });
9
10 setTimeout(function() {
11 doSomeMagic()
12 }, 500);
Function boilerplate
1
2 someArray
3 .filter(function(item) {
4 return item.isActive;
5 })
6 .map(function(item) {
7 return item.id;
8 });
9
10 setTimeout(function() {
11 doSomeMagic()
12 }, 500);
.filter(item => item.isActive)
Function boilerplate
1
2 someArray
3 .filter(function(item) {
4 return item.isActive;
5 })
6 .map(function(item) {
7 return item.id;
8 });
9
10 setTimeout(function() {
11 doSomeMagic()
12 }, 500);
.filter(item => item.isActive)
.map(item => item.id);
Function boilerplate
1
2 someArray
3 .filter(function(item) {
4 return item.isActive;
5 })
6 .map(function(item) {
7 return item.id;
8 });
9
10 setTimeout(function() {
11 doSomeMagic()
12 }, 500);
.filter(item => item.isActive)
.map(item => item.id);
setTimeout(() => {
ESNext for humans - LvivJS 16 August 2014
Things you need a
framework for
a.k.a. Goodbye Angular!
Promises
1 new Promise(function(resolve, reject) {
2 resolve('Success!');
3 // or...
4 reject('I failed!');
5 });
Native promises
Data binding
AngularJS
1 function SomeCtrl() {
2 $scope.name = "Jan";
3 }
1 <div ng-controller="SomeCtrl">
2 <input type="text" ng-model="name">
3
4 Hi {{name}}
5 </div>
Now without
a framework
From JS -> HTML
1 <div>
2 <input type="text" data-bind="name">
3 Hello <span data-bind="name"></span>
4 </div>
1 var scope = {
2 name: 'Jan'
3 };
4 // ???????
From JS -> HTML
1 <div>
2 <input type="text" data-bind="name">
3 Hello <span data-bind="name"></span>
4 </div>
1 var scope = {
2 name: 'Jan'
3 };
4 // ???????
From JS -> HTML
1 <div>
2 <input type="text" data-bind="name">
3 Hello <span data-bind="name"></span>
4 </div>
1 var scope = {
2 name: 'Jan'
3 };
4 // ???????
1 function updateScope() {
2 var els = document.querySelectorAll(
3 '*[data-bind=name]'
4 );
5
6 Array.from(els).forEach(function(el) {
7 if ('value' in el) // input element
8 el.value = scope.name;
9 else if ('textContent' in el) // normal
10 el.textContent = scope.name;
11 });
12 }
13
14 updateScope();
1 function updateScope() {
2 var els = document.querySelectorAll(
3 '*[data-bind=name]'
4 );
5
6 Array.from(els).forEach(function(el) {
7 if ('value' in el) // input element
8 el.value = scope.name;
9 else if ('textContent' in el) // normal
10 el.textContent = scope.name;
11 });
12 }
13
14 updateScope();
1 function updateScope() {
2 var els = document.querySelectorAll(
3 '*[data-bind=name]'
4 );
5
6 Array.from(els).forEach(function(el) {
7 if ('value' in el) // input element
8 el.value = scope.name;
9 else if ('textContent' in el) // normal
10 el.textContent = scope.name;
11 });
12 }
13
14 updateScope();
1 function updateScope() {
2 var els = document.querySelectorAll(
3 '*[data-bind=name]'
4 );
5
6 Array.from(els).forEach(function(el) {
7 if ('value' in el) // input element
8 el.value = scope.name;
9 else if ('textContent' in el) // normal
10 el.textContent = scope.name;
11 });
12 }
13
14 updateScope();
1 function updateScope() {
2 var els = document.querySelectorAll(
3 '*[data-bind=name]'
4 );
5
6 Array.from(els).forEach(function(el) {
7 if ('value' in el) // input element
8 el.value = scope.name;
9 else if ('textContent' in el) // normal
10 el.textContent = scope.name;
11 });
12 }
13
14 updateScope();
1 <div>
2 <input type="text" data-bind="name">
3 Hello <span data-bind="name"></span>
4 </div>
But what if we change
scope.name from JS?
1 Object.observe(scope, function(changes) {
2 changes.forEach(function(change) {
3 if (change.type === 'update' &&
4 change.name === 'name') {
5 updateScope();
6 }
7 });
8 });
9
10
11 setTimeout(function() {
12 scope.name = 'Vladimir';
13 }, 2000);
1 Object.observe(scope, function(changes) {
2 changes.forEach(function(change) {
3 if (change.type === 'update' &&
4 change.name === 'name') {
5 updateScope();
6 }
7 });
8 });
9
10
11 setTimeout(function() {
12 scope.name = 'Vladimir';
13 }, 2000);
1 Object.observe(scope, function(changes) {
2 changes.forEach(function(change) {
3 if (change.type === 'update' &&
4 change.name === 'name') {
5 updateScope();
6 }
7 });
8 });
9
10
11 setTimeout(function() {
12 scope.name = 'Vladimir';
13 }, 2000);
{ type: "update", name: "name", oldValue: "Jan"}
1 Object.observe(scope, function(changes) {
2 changes.forEach(function(change) {
3 if (change.type === 'update' &&
4 change.name === 'name') {
5 updateScope();
6 }
7 });
8 });
9
10
11 setTimeout(function() {
12 scope.name = 'Vladimir';
13 }, 2000);
{ type: "update", name: "name", oldValue: "Jan"}
ESNext for humans - LvivJS 16 August 2014
From HTML -> JS (1)
1 var els = document.querySelectorAll(
2 '*[data-bind=name]'
3 );
4
5 var observer = new MutationObserver(function() {
6 scope.name = this.textContent;
7 });
8
9 Array.from(els).forEach(function(el) {
10 observer.observe(el, { childList: true });
11 });
From HTML -> JS (1)
1 var els = document.querySelectorAll(
2 '*[data-bind=name]'
3 );
4
5 var observer = new MutationObserver(function() {
6 scope.name = this.textContent;
7 });
8
9 Array.from(els).forEach(function(el) {
10 observer.observe(el, { childList: true });
11 });
ESNext for humans - LvivJS 16 August 2014
From HTML to JS (2)
1 var els = document.querySelectorAll(
2 '*[data-bind=name]'
3 );
4
5 Array.from(els).forEach(function(el) {
6 el.onkeyup = function() {
7 if (el.value)
8 scope.name = el.value;
9 }
10 });
From HTML to JS (2)
1 var els = document.querySelectorAll(
2 '*[data-bind=name]'
3 );
4
5 Array.from(els).forEach(function(el) {
6 el.onkeyup = function() {
7 if (el.value)
8 scope.name = el.value;
9 }
10 });
ESNext for humans - LvivJS 16 August 2014
OMG AWESOME WTF
APESHIT INSANE
Things you cannot do
a.k.a. I want it now!
Proxies
Intercepting calls to objects with
JS Object
{ id: 4, city: "Lviv" }
JS Object
{ id: 4, city: "Lviv" }
Application code
JS Object
{ id: 4, city: "Lviv" }
Application code
alert(obj.id)
JS Object
{ id: 4, city: "Lviv" }
Application code
alert(obj.id)
obj.city = "Kiev"
Proxy
JS Object
{ id: 4, city: "Lviv" }
Application code
alert(obj.id)
obj.city = "Kiev"
1 var obj = new Proxy(
2 {
3 id: 4,
4 city: "Lviv"
5 },
6 {
7 get: function(target, name) {
8 console.log('Get for', name);
9 return target[name];
10 }
11 }
12 );
13
14 alert(obj.city);
15 // Get for 'city'
1 var obj = new Proxy(
2 {
3 id: 4,
4 city: "Lviv"
5 },
6 {
7 get: function(target, name) {
8 console.log('Get for', name);
9 return target[name];
10 }
11 }
12 );
13
14 alert(obj.city);
15 // Get for 'city'
1 var obj = new Proxy(
2 {
3 id: 4,
4 city: "Lviv"
5 },
6 {
7 get: function(target, name) {
8 console.log('Get for', name);
9 return target[name];
10 }
11 }
12 );
13
14 alert(obj.city);
15 // Get for 'city'
1 var obj = new Proxy(
2 {
3 id: 4,
4 city: "Lviv"
5 },
6 {
7 get: function(target, name) {
8 console.log('Get for', name);
9 return target[name];
10 }
11 }
12 );
13
14 alert(obj.city);
15 // Get for 'city'
1 var obj = new Proxy(
2 {
3 id: 4,
4 city: "Lviv"
5 },
6 {
7 get: function(target, name) {
8 if (name === 'city') {
9 return 'Kiev';
10 }
11 return target[name];
12 }
13 }
14 );
15
16 console.log(obj.city);
17 // returns 'Kiev' ?!!
1 var obj = new Proxy(
2 {
3 id: 4,
4 city: "Lviv"
5 },
6 {
7 get: function(target, name) {
8 if (name === 'city') {
9 return 'Kiev';
10 }
11 return target[name];
12 }
13 }
14 );
15
16 console.log(obj.city);
17 // returns 'Kiev' ?!!
1 var obj = new Proxy(
2 {
3 id: 4,
4 city: "Lviv"
5 },
6 {
7 get: function(target, name) {
8 if (!(name in target)) {
9 throw 'has no property "' + name + '"'
10 }
11 return target[name];
12 }
13 }
14 );
15
16 console.log(obj.citi);
ERROR: has no property 'citi'
1 var obj = new Proxy(
2 {
3 id: 4,
4 city: "Lviv"
5 },
6 {
7 get: function(target, name) {
8 if (!(name in target)) {
9 throw 'has no property "' + name + '"'
10 }
11 return target[name];
12 }
13 }
14 );
15
16 console.log(obj.citi);
ERROR: has no property 'citi'
1 var obj = new Proxy(
2 {
3 id: 4,
4 city: "Lviv"
5 },
6 {
7 set: function(target, name, value) {
8 if (name === 'id'
9 && typeof value !== 'number')
10 throw 'id must be numeric';
11 target[name] = value;
12 }
13 }
14 );
15
16 obj.id = '5';
ERROR: id must be numeric
1 var obj = new Proxy(
2 {
3 id: 4,
4 city: "Lviv"
5 },
6 {
7 set: function(target, name, value) {
8 if (name === 'id'
9 && typeof value !== 'number')
10 throw 'id must be numeric';
11 target[name] = value;
12 }
13 }
14 );
15
16 obj.id = '5';
ERROR: id must be numeric
1 set: function(target, name, value) {
2 if (target[name] !== value) {
3 console.log('Value for', name, 'changed');
4 }
5 }
Proxies are cool
Aspect Oriented Programming
Logging
Access Control
ESNext for humans - LvivJS 16 August 2014
Generators
Lazy functions
Generators
Lazy functions
Normal function
1 function normal() {
2 console.log('Hi there!');
3
4 var a = 5 + 6;
5 console.log('I think it's', a);
6
7 console.log('kthxbye');
8
9 return 3;
10 }
Generators are lazy
1 function* turingWinners () {
2 console.log('Hello from our function');
3 yield "Alan J. Perlis";
4 console.log('I returned the first one');
5 yield "Maurice Wilkes";
6 yield "Richard Hamming";
7 yield "Marvin Minsky";
8 }
9
10 turingWinners();
Generators are lazy
1 function* turingWinners () {
2 console.log('Hello from our function');
3 yield "Alan J. Perlis";
4 console.log('I returned the first one');
5 yield "Maurice Wilkes";
6 yield "Richard Hamming";
7 yield "Marvin Minsky";
8 }
9
10 turingWinners();
Generators are lazy
1 function* turingWinners () {
2 console.log('Hello from our function');
3 yield "Alan J. Perlis";
4 console.log('I returned the first one');
5 yield "Maurice Wilkes";
6 yield "Richard Hamming";
7 yield "Marvin Minsky";
8 }
9
10 turingWinners();
Generators are lazy
1 function* turingWinners () {
2 console.log('Hello from our function');
3 yield "Alan J. Perlis";
4 console.log('I returned the first one');
5 yield "Maurice Wilkes";
6 yield "Richard Hamming";
7 yield "Marvin Minsky";
8 }
9
10 turingWinners();
Generators are lazy
1 function* turingWinners () {
2 console.log('Hello from our function');
3 yield "Alan J. Perlis";
4 console.log('I returned the first one');
5 yield "Maurice Wilkes";
6 yield "Richard Hamming";
7 yield "Marvin Minsky";
8 }
9
10 turingWinners();
$ node --harmony test.js
$
Call next() to start
1 function* turingWinners () {
2 console.log('Hello from our function');
3 yield "Alan J. Perlis";
4 console.log('I returned the first one');
5 yield "Maurice Wilkes";
6 yield "Richard Hamming";
7 yield "Marvin Minsky";
8 }
9
10 var iterator = turingWinners();
11
12 console.log(iterator.next());
13 console.log(iterator.next());
Call next() to start
1 function* turingWinners () {
2 console.log('Hello from our function');
3 yield "Alan J. Perlis";
4 console.log('I returned the first one');
5 yield "Maurice Wilkes";
6 yield "Richard Hamming";
7 yield "Marvin Minsky";
8 }
9
10 var iterator = turingWinners();
11
12 console.log(iterator.next());
13 console.log(iterator.next());
Call next() to start
1 function* turingWinners () {
2 console.log('Hello from our function');
3 yield "Alan J. Perlis";
4 console.log('I returned the first one');
5 yield "Maurice Wilkes";
6 yield "Richard Hamming";
7 yield "Marvin Minsky";
8 }
9
10 var iterator = turingWinners();
11
12 console.log(iterator.next());
13 console.log(iterator.next());
Call next() to start
1 function* turingWinners () {
2 console.log('Hello from our function');
3 yield "Alan J. Perlis";
4 console.log('I returned the first one');
5 yield "Maurice Wilkes";
6 yield "Richard Hamming";
7 yield "Marvin Minsky";
8 }
9
10 var iterator = turingWinners();
11
12 console.log(iterator.next());
13 console.log(iterator.next());
$ node --harmony test.js
Hello from our function
{ value: 'Alan J. Perlis', done: false }
Call next() to start
1 function* turingWinners () {
2 console.log('Hello from our function');
3 yield "Alan J. Perlis";
4 console.log('I returned the first one');
5 yield "Maurice Wilkes";
6 yield "Richard Hamming";
7 yield "Marvin Minsky";
8 }
9
10 var iterator = turingWinners();
11
12 console.log(iterator.next());
13 console.log(iterator.next());
Call next() to start
1 function* turingWinners () {
2 console.log('Hello from our function');
3 yield "Alan J. Perlis";
4 console.log('I returned the first one');
5 yield "Maurice Wilkes";
6 yield "Richard Hamming";
7 yield "Marvin Minsky";
8 }
9
10 var iterator = turingWinners();
11
12 console.log(iterator.next());
13 console.log(iterator.next());
Call next() to start
1 function* turingWinners () {
2 console.log('Hello from our function');
3 yield "Alan J. Perlis";
4 console.log('I returned the first one');
5 yield "Maurice Wilkes";
6 yield "Richard Hamming";
7 yield "Marvin Minsky";
8 }
9
10 var iterator = turingWinners();
11
12 console.log(iterator.next());
13 console.log(iterator.next());
$ node --harmony test.js
Hello from our function
{ value: 'Alan J. Perlis', done: false }
I returned the first one
{ value: 'Maurice Wilkes', done: false }
Inef!cient thing in JS
1 var nice = [1,2,3,4,5,6,7,8,9,10,11,12]
2 .filter(function(v) {
3 return v % 2 === 0;
4 })
5 .map(function(v) {
6 return v * v;
7 })
8 .slice(0, 3);
9
10 console.log(nice);
Inef!cient thing in JS
1 var nice = [1,2,3,4,5,6,7,8,9,10,11,12]
2 .filter(function(v) {
3 return v % 2 === 0;
4 })
5 .map(function(v) {
6 return v * v;
7 })
8 .slice(0, 3);
9
10 console.log(nice);
Inef!cient thing in JS
1 var nice = [1,2,3,4,5,6,7,8,9,10,11,12]
2 .filter(function(v) {
3 return v % 2 === 0;
4 })
5 .map(function(v) {
6 return v * v;
7 })
8 .slice(0, 3);
9
10 console.log(nice);
Inef!cient thing in JS
1 var nice = [1,2,3,4,5,6,7,8,9,10,11,12]
2 .filter(function(v) {
3 return v % 2 === 0;
4 })
5 .map(function(v) {
6 return v * v;
7 })
8 .slice(0, 3);
9
10 console.log(nice);
Inef!cient thing in JS
1 var nice = [1,2,3,4,5,6,7,8,9,10,11,12]
2 .filter(function(v) {
3 return v % 2 === 0;
4 })
5 .map(function(v) {
6 return v * v;
7 })
8 .slice(0, 3);
9
10 console.log(nice);
1 function* generateNumber() {
2 var i = 0;
3 while (true)
4 yield ++i;
5 }
6
7 function* filter(it) {
8 for (var n of it)
9 if (n % 2 == 0) yield curr;
10 }
11
12 function* map(it) {
13 for (var n of it)
14 yield n * n;
15 }
1 function* generateNumber() {
2 var i = 0;
3 while (true)
4 yield ++i;
5 }
6
7 function* filter(it) {
8 for (var n of it)
9 if (n % 2 == 0) yield curr;
10 }
11
12 function* map(it) {
13 for (var n of it)
14 yield n * n;
15 }
1 function* generateNumber() {
2 var i = 0;
3 while (true)
4 yield ++i;
5 }
6
7 function* filter(it) {
8 for (var n of it)
9 if (n % 2 == 0) yield curr;
10 }
11
12 function* map(it) {
13 for (var n of it)
14 yield n * n;
15 }
1,2,3,4,5,6
1 function* generateNumber() {
2 var i = 0;
3 while (true)
4 yield ++i;
5 }
6
7 function* filter(it) {
8 for (var n of it)
9 if (n % 2 == 0) yield curr;
10 }
11
12 function* map(it) {
13 for (var n of it)
14 yield n * n;
15 }
1,2,3,4,5,6
1 function* generateNumber() {
2 var i = 0;
3 while (true)
4 yield ++i;
5 }
6
7 function* filter(it) {
8 for (var n of it)
9 if (n % 2 == 0) yield curr;
10 }
11
12 function* map(it) {
13 for (var n of it)
14 yield n * n;
15 }
1,2,3,4,5,6
n%2 == 0
2,4,6
1 function* generateNumber() {
2 var i = 0;
3 while (true)
4 yield ++i;
5 }
6
7 function* filter(it) {
8 for (var n of it)
9 if (n % 2 == 0) yield curr;
10 }
11
12 function* map(it) {
13 for (var n of it)
14 yield n * n;
15 }
1,2,3,4,5,6
n%2 == 0
2,4,6
1 function* generateNumber() {
2 var i = 0;
3 while (true)
4 yield ++i;
5 }
6
7 function* filter(it) {
8 for (var n of it)
9 if (n % 2 == 0) yield curr;
10 }
11
12 function* map(it) {
13 for (var n of it)
14 yield n * n;
15 }
1,2,3,4,5,6
n%2 == 0
2,4,6
n * n
4,16,36
Using the generators
1 var nice = generateNumber();
2 nice = filter(nice);
3 nice = map(nice);
4
5 for (var i = 0; i < 3; i++) {
6 console.log(i, nice.next().value);
7 }
Using the generators
1 var nice = generateNumber();
2 nice = filter(nice);
3 nice = map(nice);
4
5 for (var i = 0; i < 3; i++) {
6 console.log(i, nice.next().value);
7 }
ESNext for humans - LvivJS 16 August 2014
Two way interaction
1 function* printName() {
2 var name = yield 'Whats your name?';
3 console.log('Hello', name);
4 }
5
6 var iterator = printName();
7 console.log('It:', iterator.next().value);
8
9 setTimeout(function() {
10 var ret = iterator.next('Jan Jongboom');
11 console.log(ret);
12 }, 1000);
Two way interaction
1 function* printName() {
2 var name = yield 'Whats your name?';
3 console.log('Hello', name);
4 }
5
6 var iterator = printName();
7 console.log('It:', iterator.next().value);
8
9 setTimeout(function() {
10 var ret = iterator.next('Jan Jongboom');
11 console.log(ret);
12 }, 1000);
Two way interaction
1 function* printName() {
2 var name = yield 'Whats your name?';
3 console.log('Hello', name);
4 }
5
6 var iterator = printName();
7 console.log('It:', iterator.next().value);
8
9 setTimeout(function() {
10 var ret = iterator.next('Jan Jongboom');
11 console.log(ret);
12 }, 1000);
Two way interaction
1 function* printName() {
2 var name = yield 'Whats your name?';
3 console.log('Hello', name);
4 }
5
6 var iterator = printName();
7 console.log('It:', iterator.next().value);
8
9 setTimeout(function() {
10 var ret = iterator.next('Jan Jongboom');
11 console.log(ret);
12 }, 1000);
Two way interaction
1 function* printName() {
2 var name = yield 'Whats your name?';
3 console.log('Hello', name);
4 }
5
6 var iterator = printName();
7 console.log('It:', iterator.next().value);
8
9 setTimeout(function() {
10 var ret = iterator.next('Jan Jongboom');
11 console.log(ret);
12 }, 1000);
Two way interaction
1 function* printName() {
2 var name = yield 'Whats your name?';
3 console.log('Hello', name);
4 }
5
6 var iterator = printName();
7 console.log('It:', iterator.next().value);
8
9 setTimeout(function() {
10 var ret = iterator.next('Jan Jongboom');
11 console.log(ret);
12 }, 1000);
Two way interaction
1 function* printName() {
2 var name = yield 'Whats your name?';
3 console.log('Hello', name);
4 }
5
6 var iterator = printName();
7 console.log('It:', iterator.next().value);
8
9 setTimeout(function() {
10 var ret = iterator.next('Jan Jongboom');
11 console.log(ret);
12 }, 1000);
$ node --harmony test.js
It: Whats your name?
Two way interaction
1 function* printName() {
2 var name = yield 'Whats your name?';
3 console.log('Hello', name);
4 }
5
6 var iterator = printName();
7 console.log('It:', iterator.next().value);
8
9 setTimeout(function() {
10 var ret = iterator.next('Jan Jongboom');
11 console.log(ret);
12 }, 1000);
$ node --harmony test.js
It: Whats your name?
$ node --harmony test.js
It: Whats your name?
Hello Jan Jongboom
{ value: undefined, done: true }
Yield and deferred values
• Wrote sync code
• But yield waits until new value comes in...
• So it’s actually async with sync syntax
• We need to abuse this!
1 function* printName() {
2 var name = yield 'Whats your name?';
3 console.log('Hello', name);
4 }
1 function* run() {
2 yield sleep(2000);
3 console.log('It has been 2 seconds');
4 }
5
6 function sleep(ms) {
7 return new Promise((res, rej) => {
8 setTimeout(res, ms);
9 });
10 }
11
12 var it = run();
13 var ret = it.next().value;
14
15 ret.then(function() {
16 it.next();
17 });
1 function* run() {
2 yield sleep(2000);
3 console.log('It has been 2 seconds');
4 }
5
6 function sleep(ms) {
7 return new Promise((res, rej) => {
8 setTimeout(res, ms);
9 });
10 }
11
12 var it = run();
13 var ret = it.next().value;
14
15 ret.then(function() {
16 it.next();
17 });
1 function* run() {
2 yield sleep(2000);
3 console.log('It has been 2 seconds');
4 }
5
6 function sleep(ms) {
7 return new Promise((res, rej) => {
8 setTimeout(res, ms);
9 });
10 }
11
12 var it = run();
13 var ret = it.next().value;
14
15 ret.then(function() {
16 it.next();
17 });
1 function* run() {
2 yield sleep(2000);
3 console.log('It has been 2 seconds');
4 }
5
6 function sleep(ms) {
7 return new Promise((res, rej) => {
8 setTimeout(res, ms);
9 });
10 }
11
12 var it = run();
13 var ret = it.next().value;
14
15 ret.then(function() {
16 it.next();
17 });
1 function* run() {
2 yield sleep(2000);
3 console.log('It has been 2 seconds');
4 }
5
6 function sleep(ms) {
7 return new Promise((res, rej) => {
8 setTimeout(res, ms);
9 });
10 }
11
12 var it = run();
13 var ret = it.next().value;
14
15 ret.then(function() {
16 it.next();
17 });
1 function* run() {
2 yield sleep(2000);
3 console.log('It has been 2 seconds');
4 }
5
6 function sleep(ms) {
7 return new Promise((res, rej) => {
8 setTimeout(res, ms);
9 });
10 }
11
12 var it = run();
13 var ret = it.next().value;
14
15 ret.then(function() {
16 it.next();
17 });
1 function* run() {
2 yield sleep(2000);
3 console.log('It has been 2 seconds');
4 }
5
6 function sleep(ms) {
7 return new Promise((res, rej) => {
8 setTimeout(res, ms);
9 });
10 }
11
12 var it = run();
13 var ret = it.next().value;
14
15 ret.then(function() {
16 it.next();
17 });
1 function* run() {
2 yield sleep(2000);
3 console.log('It has been 2 seconds');
4 }
5
6 function sleep(ms) {
7 return new Promise((res, rej) => {
8 setTimeout(res, ms);
9 });
10 }
11
12 var it = run();
13 var ret = it.next().value;
14
15 ret.then(function() {
16 it.next();
17 });
1 function* run() {
2 yield sleep(2000);
3 console.log('It has been 2 seconds');
4 }
5
6 function sleep(ms) {
7 return new Promise((res, rej) => {
8 setTimeout(res, ms);
9 });
10 }
11
12 var it = run();
13 var ret = it.next().value;
14
15 ret.then(function() {
16 it.next();
17 });
http://pag.forbeslindesay.co.uk/#/22
1 run(function* () {
2 var data = yield $.get('/yolo');
3 data = JSON.parse(data);
4 });
http://pag.forbeslindesay.co.uk/#/22
1 run(function* () {
2 try {
3 var moar = yield $.post('/other');
4 }
5 catch (ex) {
6 console.error('Oh noes!', ex);
7 }
8 });
http://pag.forbeslindesay.co.uk/#/22
1 run(function* () {
2 var req1 = $.get('http://a');
3 var req2 = $.get('http://b');
4
5 $('.status').text(
yield req1 + yield req2);
6 });
OMGAWESOME
ESNext for humans - LvivJS 16 August 2014
ESNext for humans - LvivJS 16 August 2014
Thank you!
slideshare.net/janjongboom
slideshare.net/janjongboom
Questions?

More Related Content

ESNext for humans - LvivJS 16 August 2014

  • 10. програма Things you could already do Things you needed a framework for Things that were impossible
  • 11. Things you can already do alt: S*#t that annoys Jan in JavaScript
  • 12. NodeList is not an array 1 document.querySelectorAll('li') 2 .filter(function(li) { 3 /* do something */ 4 }); 5 ERROR: document.querySelectorAll(...).filter is not a function
  • 13. NodeList is not an array 1 Array.prototype.slice.call( 2 document.querySelectorAll('li') 3 )
  • 14. NodeList is not an array 1 Array.prototype.slice.call( 2 document.querySelectorAll('li') 3 ) 1 Array.from( 2 document.querySelectorAll('li') 3 )
  • 15. Variable scoping 1 var a = 7; 2 3 if (something) { 4 var a = 9; 5 doSomethingElse(a); 6 } 7 8 console.log(a);
  • 16. Variable scoping 1 var a = 7; 2 3 if (something) { 4 var a = 9; 5 doSomethingElse(a); 6 } 7 8 console.log(a); // can be 7 or 9 depending on 'something'
  • 17. Variable scoping 1 var a = 7; 2 3 if (something) { 4 var a = 9; 5 doSomethingElse(a); 6 } 7 8 console.log(a); // can be 7 or 9 depending on 'something'
  • 18. Variable scoping 1 var a = 7; 2 3 if (something) { 4 var a = 9; 5 doSomethingElse(a); 6 } 7 8 console.log(a); // can be 7 or 9 depending on 'something'
  • 19. Variable scoping 1 let a = 7; 2 3 if (something) { 4 let a = 9; 5 doSomethingElse(a); 6 } 7 8 console.log(a); // always 7 ‘let’ to the rescue
  • 20. Variable scoping 1 let a = 7; 2 3 if (something) { 4 let a = 9; 5 doSomethingElse(a); 6 } 7 8 console.log(a); // always 7 ‘let’ to the rescue
  • 22. 1 function getPosition() { 2 return [ 12, 91 ]; 3 } 4 5 var pos = getPosition(); 6 var x = pos[0], 7 y = pos[1]; 8 9 function getPosition() { 10 return { x: 12, y: 91 }; 11 } 12 13 var pos = getPosition(); 14 var x = pos.x; 15 y = pos.y;
  • 23. 1 function getPosition() { 2 return [ 12, 91 ]; 3 } 4 5 var pos = getPosition(); 6 var x = pos[0], 7 y = pos[1]; 8 9 function getPosition() { 10 return { x: 12, y: 91 }; 11 } 12 13 var pos = getPosition(); 14 var x = pos.x; 15 y = pos.y; let [x, y] = getPosition();
  • 24. 1 function getPosition() { 2 return [ 12, 91 ]; 3 } 4 5 var pos = getPosition(); 6 var x = pos[0], 7 y = pos[1]; 8 9 function getPosition() { 10 return { x: 12, y: 91 }; 11 } 12 13 var pos = getPosition(); 14 var x = pos.x; 15 y = pos.y; let [x, y] = getPosition(); let {x, y} = getPosition();
  • 25. 1 var data = {}; 2 3 data['jan'] = 'awesome'; 4 data['pete'] = 'not so awesome'; 5 6 var ele1 = document.querySelector('#el1'); 7 data[ele1] = 'first element'; 8 9 var ele2 = document.querySelector('#el2'); 10 data[ele2] = 'second element'; 11 12 console.log(data[ele1]); Maps
  • 26. 1 var data = {}; 2 3 data['jan'] = 'awesome'; 4 data['pete'] = 'not so awesome'; 5 6 var ele1 = document.querySelector('#el1'); 7 data[ele1] = 'first element'; 8 9 var ele2 = document.querySelector('#el2'); 10 data[ele2] = 'second element'; 11 12 console.log(data[ele1]); Maps
  • 27. 1 var data = {}; 2 3 data['jan'] = 'awesome'; 4 data['pete'] = 'not so awesome'; 5 6 var ele1 = document.querySelector('#el1'); 7 data[ele1] = 'first element'; 8 9 var ele2 = document.querySelector('#el2'); 10 data[ele2] = 'second element'; 11 12 console.log(data[ele1]); Maps “second element”
  • 28. 1 var data = {}; 2 3 data['jan'] = 'awesome'; 4 data['pete'] = 'not so awesome'; 5 6 var ele1 = document.querySelector('#el1'); 7 data[ele1] = 'first element'; 8 9 var ele2 = document.querySelector('#el2'); 10 data[ele2] = 'second element'; 11 12 console.log(data[ele1]); Maps
  • 29. Maps 1 var data = {}; 2 3 data['jan'] = 'awesome'; 4 data['pete'] = 'not so awesome'; 5 6 var ele1 = document.querySelector('#el1'); 7 data[ele1] = 'first element'; 8 9 var ele2 = document.querySelector('#el2'); 10 data[ele2] = 'second element'; 11 12 console.log(data[ele1]);
  • 30. Maps 1 var data = {}; 2 3 data['jan'] = 'awesome'; 4 data['pete'] = 'not so awesome'; 5 6 var ele1 = document.querySelector('#el1'); 7 data[ele1] = 'first element'; 8 9 var ele2 = document.querySelector('#el2'); 10 data[ele2] = 'second element'; 11 12 console.log(data[ele1]); data[ele2.toString()] ele2.toString() => “[object HTMLDivElement”]
  • 31. Maps 1 var data = new Map(); 2 3 data.set('jan', 'awesome'); 4 5 data.has('jan'); // true 6 data.get('jan'); // "awesome" 7 8 var ele1 = document.querySelector('#el1'); 9 data.set(ele1, 'first element'); 10 11 var ele2 = document.querySelector('#el2'); 12 data.set(ele2, 'second element'); 13 14 console.log(data.get(ele1)); // "first element"
  • 32. Maps 1 var data = new Map(); 2 3 data.set('jan', 'awesome'); 4 5 data.has('jan'); // true 6 data.get('jan'); // "awesome" 7 8 var ele1 = document.querySelector('#el1'); 9 data.set(ele1, 'first element'); 10 11 var ele2 = document.querySelector('#el2'); 12 data.set(ele2, 'second element'); 13 14 console.log(data.get(ele1)); // "first element"
  • 33. Function boilerplate 1 2 someArray 3 .filter(function(item) { 4 return item.isActive; 5 }) 6 .map(function(item) { 7 return item.id; 8 }); 9 10 setTimeout(function() { 11 doSomeMagic() 12 }, 500);
  • 34. Function boilerplate 1 2 someArray 3 .filter(function(item) { 4 return item.isActive; 5 }) 6 .map(function(item) { 7 return item.id; 8 }); 9 10 setTimeout(function() { 11 doSomeMagic() 12 }, 500); .filter(item => item.isActive)
  • 35. Function boilerplate 1 2 someArray 3 .filter(function(item) { 4 return item.isActive; 5 }) 6 .map(function(item) { 7 return item.id; 8 }); 9 10 setTimeout(function() { 11 doSomeMagic() 12 }, 500); .filter(item => item.isActive) .map(item => item.id);
  • 36. Function boilerplate 1 2 someArray 3 .filter(function(item) { 4 return item.isActive; 5 }) 6 .map(function(item) { 7 return item.id; 8 }); 9 10 setTimeout(function() { 11 doSomeMagic() 12 }, 500); .filter(item => item.isActive) .map(item => item.id); setTimeout(() => {
  • 38. Things you need a framework for a.k.a. Goodbye Angular!
  • 40. 1 new Promise(function(resolve, reject) { 2 resolve('Success!'); 3 // or... 4 reject('I failed!'); 5 }); Native promises
  • 42. AngularJS 1 function SomeCtrl() { 2 $scope.name = "Jan"; 3 } 1 <div ng-controller="SomeCtrl"> 2 <input type="text" ng-model="name"> 3 4 Hi {{name}} 5 </div>
  • 44. From JS -> HTML 1 <div> 2 <input type="text" data-bind="name"> 3 Hello <span data-bind="name"></span> 4 </div> 1 var scope = { 2 name: 'Jan' 3 }; 4 // ???????
  • 45. From JS -> HTML 1 <div> 2 <input type="text" data-bind="name"> 3 Hello <span data-bind="name"></span> 4 </div> 1 var scope = { 2 name: 'Jan' 3 }; 4 // ???????
  • 46. From JS -> HTML 1 <div> 2 <input type="text" data-bind="name"> 3 Hello <span data-bind="name"></span> 4 </div> 1 var scope = { 2 name: 'Jan' 3 }; 4 // ???????
  • 47. 1 function updateScope() { 2 var els = document.querySelectorAll( 3 '*[data-bind=name]' 4 ); 5 6 Array.from(els).forEach(function(el) { 7 if ('value' in el) // input element 8 el.value = scope.name; 9 else if ('textContent' in el) // normal 10 el.textContent = scope.name; 11 }); 12 } 13 14 updateScope();
  • 48. 1 function updateScope() { 2 var els = document.querySelectorAll( 3 '*[data-bind=name]' 4 ); 5 6 Array.from(els).forEach(function(el) { 7 if ('value' in el) // input element 8 el.value = scope.name; 9 else if ('textContent' in el) // normal 10 el.textContent = scope.name; 11 }); 12 } 13 14 updateScope();
  • 49. 1 function updateScope() { 2 var els = document.querySelectorAll( 3 '*[data-bind=name]' 4 ); 5 6 Array.from(els).forEach(function(el) { 7 if ('value' in el) // input element 8 el.value = scope.name; 9 else if ('textContent' in el) // normal 10 el.textContent = scope.name; 11 }); 12 } 13 14 updateScope();
  • 50. 1 function updateScope() { 2 var els = document.querySelectorAll( 3 '*[data-bind=name]' 4 ); 5 6 Array.from(els).forEach(function(el) { 7 if ('value' in el) // input element 8 el.value = scope.name; 9 else if ('textContent' in el) // normal 10 el.textContent = scope.name; 11 }); 12 } 13 14 updateScope();
  • 51. 1 function updateScope() { 2 var els = document.querySelectorAll( 3 '*[data-bind=name]' 4 ); 5 6 Array.from(els).forEach(function(el) { 7 if ('value' in el) // input element 8 el.value = scope.name; 9 else if ('textContent' in el) // normal 10 el.textContent = scope.name; 11 }); 12 } 13 14 updateScope(); 1 <div> 2 <input type="text" data-bind="name"> 3 Hello <span data-bind="name"></span> 4 </div>
  • 52. But what if we change scope.name from JS?
  • 53. 1 Object.observe(scope, function(changes) { 2 changes.forEach(function(change) { 3 if (change.type === 'update' && 4 change.name === 'name') { 5 updateScope(); 6 } 7 }); 8 }); 9 10 11 setTimeout(function() { 12 scope.name = 'Vladimir'; 13 }, 2000);
  • 54. 1 Object.observe(scope, function(changes) { 2 changes.forEach(function(change) { 3 if (change.type === 'update' && 4 change.name === 'name') { 5 updateScope(); 6 } 7 }); 8 }); 9 10 11 setTimeout(function() { 12 scope.name = 'Vladimir'; 13 }, 2000);
  • 55. 1 Object.observe(scope, function(changes) { 2 changes.forEach(function(change) { 3 if (change.type === 'update' && 4 change.name === 'name') { 5 updateScope(); 6 } 7 }); 8 }); 9 10 11 setTimeout(function() { 12 scope.name = 'Vladimir'; 13 }, 2000); { type: "update", name: "name", oldValue: "Jan"}
  • 56. 1 Object.observe(scope, function(changes) { 2 changes.forEach(function(change) { 3 if (change.type === 'update' && 4 change.name === 'name') { 5 updateScope(); 6 } 7 }); 8 }); 9 10 11 setTimeout(function() { 12 scope.name = 'Vladimir'; 13 }, 2000); { type: "update", name: "name", oldValue: "Jan"}
  • 58. From HTML -> JS (1) 1 var els = document.querySelectorAll( 2 '*[data-bind=name]' 3 ); 4 5 var observer = new MutationObserver(function() { 6 scope.name = this.textContent; 7 }); 8 9 Array.from(els).forEach(function(el) { 10 observer.observe(el, { childList: true }); 11 });
  • 59. From HTML -> JS (1) 1 var els = document.querySelectorAll( 2 '*[data-bind=name]' 3 ); 4 5 var observer = new MutationObserver(function() { 6 scope.name = this.textContent; 7 }); 8 9 Array.from(els).forEach(function(el) { 10 observer.observe(el, { childList: true }); 11 });
  • 61. From HTML to JS (2) 1 var els = document.querySelectorAll( 2 '*[data-bind=name]' 3 ); 4 5 Array.from(els).forEach(function(el) { 6 el.onkeyup = function() { 7 if (el.value) 8 scope.name = el.value; 9 } 10 });
  • 62. From HTML to JS (2) 1 var els = document.querySelectorAll( 2 '*[data-bind=name]' 3 ); 4 5 Array.from(els).forEach(function(el) { 6 el.onkeyup = function() { 7 if (el.value) 8 scope.name = el.value; 9 } 10 });
  • 65. Things you cannot do a.k.a. I want it now!
  • 67. JS Object { id: 4, city: "Lviv" }
  • 68. JS Object { id: 4, city: "Lviv" } Application code
  • 69. JS Object { id: 4, city: "Lviv" } Application code alert(obj.id)
  • 70. JS Object { id: 4, city: "Lviv" } Application code alert(obj.id) obj.city = "Kiev"
  • 71. Proxy JS Object { id: 4, city: "Lviv" } Application code alert(obj.id) obj.city = "Kiev"
  • 72. 1 var obj = new Proxy( 2 { 3 id: 4, 4 city: "Lviv" 5 }, 6 { 7 get: function(target, name) { 8 console.log('Get for', name); 9 return target[name]; 10 } 11 } 12 ); 13 14 alert(obj.city); 15 // Get for 'city'
  • 73. 1 var obj = new Proxy( 2 { 3 id: 4, 4 city: "Lviv" 5 }, 6 { 7 get: function(target, name) { 8 console.log('Get for', name); 9 return target[name]; 10 } 11 } 12 ); 13 14 alert(obj.city); 15 // Get for 'city'
  • 74. 1 var obj = new Proxy( 2 { 3 id: 4, 4 city: "Lviv" 5 }, 6 { 7 get: function(target, name) { 8 console.log('Get for', name); 9 return target[name]; 10 } 11 } 12 ); 13 14 alert(obj.city); 15 // Get for 'city'
  • 75. 1 var obj = new Proxy( 2 { 3 id: 4, 4 city: "Lviv" 5 }, 6 { 7 get: function(target, name) { 8 console.log('Get for', name); 9 return target[name]; 10 } 11 } 12 ); 13 14 alert(obj.city); 15 // Get for 'city'
  • 76. 1 var obj = new Proxy( 2 { 3 id: 4, 4 city: "Lviv" 5 }, 6 { 7 get: function(target, name) { 8 if (name === 'city') { 9 return 'Kiev'; 10 } 11 return target[name]; 12 } 13 } 14 ); 15 16 console.log(obj.city); 17 // returns 'Kiev' ?!!
  • 77. 1 var obj = new Proxy( 2 { 3 id: 4, 4 city: "Lviv" 5 }, 6 { 7 get: function(target, name) { 8 if (name === 'city') { 9 return 'Kiev'; 10 } 11 return target[name]; 12 } 13 } 14 ); 15 16 console.log(obj.city); 17 // returns 'Kiev' ?!!
  • 78. 1 var obj = new Proxy( 2 { 3 id: 4, 4 city: "Lviv" 5 }, 6 { 7 get: function(target, name) { 8 if (!(name in target)) { 9 throw 'has no property "' + name + '"' 10 } 11 return target[name]; 12 } 13 } 14 ); 15 16 console.log(obj.citi); ERROR: has no property 'citi'
  • 79. 1 var obj = new Proxy( 2 { 3 id: 4, 4 city: "Lviv" 5 }, 6 { 7 get: function(target, name) { 8 if (!(name in target)) { 9 throw 'has no property "' + name + '"' 10 } 11 return target[name]; 12 } 13 } 14 ); 15 16 console.log(obj.citi); ERROR: has no property 'citi'
  • 80. 1 var obj = new Proxy( 2 { 3 id: 4, 4 city: "Lviv" 5 }, 6 { 7 set: function(target, name, value) { 8 if (name === 'id' 9 && typeof value !== 'number') 10 throw 'id must be numeric'; 11 target[name] = value; 12 } 13 } 14 ); 15 16 obj.id = '5'; ERROR: id must be numeric
  • 81. 1 var obj = new Proxy( 2 { 3 id: 4, 4 city: "Lviv" 5 }, 6 { 7 set: function(target, name, value) { 8 if (name === 'id' 9 && typeof value !== 'number') 10 throw 'id must be numeric'; 11 target[name] = value; 12 } 13 } 14 ); 15 16 obj.id = '5'; ERROR: id must be numeric
  • 82. 1 set: function(target, name, value) { 2 if (target[name] !== value) { 3 console.log('Value for', name, 'changed'); 4 } 5 }
  • 83. Proxies are cool Aspect Oriented Programming Logging Access Control
  • 87. Normal function 1 function normal() { 2 console.log('Hi there!'); 3 4 var a = 5 + 6; 5 console.log('I think it's', a); 6 7 console.log('kthxbye'); 8 9 return 3; 10 }
  • 88. Generators are lazy 1 function* turingWinners () { 2 console.log('Hello from our function'); 3 yield "Alan J. Perlis"; 4 console.log('I returned the first one'); 5 yield "Maurice Wilkes"; 6 yield "Richard Hamming"; 7 yield "Marvin Minsky"; 8 } 9 10 turingWinners();
  • 89. Generators are lazy 1 function* turingWinners () { 2 console.log('Hello from our function'); 3 yield "Alan J. Perlis"; 4 console.log('I returned the first one'); 5 yield "Maurice Wilkes"; 6 yield "Richard Hamming"; 7 yield "Marvin Minsky"; 8 } 9 10 turingWinners();
  • 90. Generators are lazy 1 function* turingWinners () { 2 console.log('Hello from our function'); 3 yield "Alan J. Perlis"; 4 console.log('I returned the first one'); 5 yield "Maurice Wilkes"; 6 yield "Richard Hamming"; 7 yield "Marvin Minsky"; 8 } 9 10 turingWinners();
  • 91. Generators are lazy 1 function* turingWinners () { 2 console.log('Hello from our function'); 3 yield "Alan J. Perlis"; 4 console.log('I returned the first one'); 5 yield "Maurice Wilkes"; 6 yield "Richard Hamming"; 7 yield "Marvin Minsky"; 8 } 9 10 turingWinners();
  • 92. Generators are lazy 1 function* turingWinners () { 2 console.log('Hello from our function'); 3 yield "Alan J. Perlis"; 4 console.log('I returned the first one'); 5 yield "Maurice Wilkes"; 6 yield "Richard Hamming"; 7 yield "Marvin Minsky"; 8 } 9 10 turingWinners(); $ node --harmony test.js $
  • 93. Call next() to start 1 function* turingWinners () { 2 console.log('Hello from our function'); 3 yield "Alan J. Perlis"; 4 console.log('I returned the first one'); 5 yield "Maurice Wilkes"; 6 yield "Richard Hamming"; 7 yield "Marvin Minsky"; 8 } 9 10 var iterator = turingWinners(); 11 12 console.log(iterator.next()); 13 console.log(iterator.next());
  • 94. Call next() to start 1 function* turingWinners () { 2 console.log('Hello from our function'); 3 yield "Alan J. Perlis"; 4 console.log('I returned the first one'); 5 yield "Maurice Wilkes"; 6 yield "Richard Hamming"; 7 yield "Marvin Minsky"; 8 } 9 10 var iterator = turingWinners(); 11 12 console.log(iterator.next()); 13 console.log(iterator.next());
  • 95. Call next() to start 1 function* turingWinners () { 2 console.log('Hello from our function'); 3 yield "Alan J. Perlis"; 4 console.log('I returned the first one'); 5 yield "Maurice Wilkes"; 6 yield "Richard Hamming"; 7 yield "Marvin Minsky"; 8 } 9 10 var iterator = turingWinners(); 11 12 console.log(iterator.next()); 13 console.log(iterator.next());
  • 96. Call next() to start 1 function* turingWinners () { 2 console.log('Hello from our function'); 3 yield "Alan J. Perlis"; 4 console.log('I returned the first one'); 5 yield "Maurice Wilkes"; 6 yield "Richard Hamming"; 7 yield "Marvin Minsky"; 8 } 9 10 var iterator = turingWinners(); 11 12 console.log(iterator.next()); 13 console.log(iterator.next()); $ node --harmony test.js Hello from our function { value: 'Alan J. Perlis', done: false }
  • 97. Call next() to start 1 function* turingWinners () { 2 console.log('Hello from our function'); 3 yield "Alan J. Perlis"; 4 console.log('I returned the first one'); 5 yield "Maurice Wilkes"; 6 yield "Richard Hamming"; 7 yield "Marvin Minsky"; 8 } 9 10 var iterator = turingWinners(); 11 12 console.log(iterator.next()); 13 console.log(iterator.next());
  • 98. Call next() to start 1 function* turingWinners () { 2 console.log('Hello from our function'); 3 yield "Alan J. Perlis"; 4 console.log('I returned the first one'); 5 yield "Maurice Wilkes"; 6 yield "Richard Hamming"; 7 yield "Marvin Minsky"; 8 } 9 10 var iterator = turingWinners(); 11 12 console.log(iterator.next()); 13 console.log(iterator.next());
  • 99. Call next() to start 1 function* turingWinners () { 2 console.log('Hello from our function'); 3 yield "Alan J. Perlis"; 4 console.log('I returned the first one'); 5 yield "Maurice Wilkes"; 6 yield "Richard Hamming"; 7 yield "Marvin Minsky"; 8 } 9 10 var iterator = turingWinners(); 11 12 console.log(iterator.next()); 13 console.log(iterator.next()); $ node --harmony test.js Hello from our function { value: 'Alan J. Perlis', done: false } I returned the first one { value: 'Maurice Wilkes', done: false }
  • 100. Inef!cient thing in JS 1 var nice = [1,2,3,4,5,6,7,8,9,10,11,12] 2 .filter(function(v) { 3 return v % 2 === 0; 4 }) 5 .map(function(v) { 6 return v * v; 7 }) 8 .slice(0, 3); 9 10 console.log(nice);
  • 101. Inef!cient thing in JS 1 var nice = [1,2,3,4,5,6,7,8,9,10,11,12] 2 .filter(function(v) { 3 return v % 2 === 0; 4 }) 5 .map(function(v) { 6 return v * v; 7 }) 8 .slice(0, 3); 9 10 console.log(nice);
  • 102. Inef!cient thing in JS 1 var nice = [1,2,3,4,5,6,7,8,9,10,11,12] 2 .filter(function(v) { 3 return v % 2 === 0; 4 }) 5 .map(function(v) { 6 return v * v; 7 }) 8 .slice(0, 3); 9 10 console.log(nice);
  • 103. Inef!cient thing in JS 1 var nice = [1,2,3,4,5,6,7,8,9,10,11,12] 2 .filter(function(v) { 3 return v % 2 === 0; 4 }) 5 .map(function(v) { 6 return v * v; 7 }) 8 .slice(0, 3); 9 10 console.log(nice);
  • 104. Inef!cient thing in JS 1 var nice = [1,2,3,4,5,6,7,8,9,10,11,12] 2 .filter(function(v) { 3 return v % 2 === 0; 4 }) 5 .map(function(v) { 6 return v * v; 7 }) 8 .slice(0, 3); 9 10 console.log(nice);
  • 105. 1 function* generateNumber() { 2 var i = 0; 3 while (true) 4 yield ++i; 5 } 6 7 function* filter(it) { 8 for (var n of it) 9 if (n % 2 == 0) yield curr; 10 } 11 12 function* map(it) { 13 for (var n of it) 14 yield n * n; 15 }
  • 106. 1 function* generateNumber() { 2 var i = 0; 3 while (true) 4 yield ++i; 5 } 6 7 function* filter(it) { 8 for (var n of it) 9 if (n % 2 == 0) yield curr; 10 } 11 12 function* map(it) { 13 for (var n of it) 14 yield n * n; 15 }
  • 107. 1 function* generateNumber() { 2 var i = 0; 3 while (true) 4 yield ++i; 5 } 6 7 function* filter(it) { 8 for (var n of it) 9 if (n % 2 == 0) yield curr; 10 } 11 12 function* map(it) { 13 for (var n of it) 14 yield n * n; 15 } 1,2,3,4,5,6
  • 108. 1 function* generateNumber() { 2 var i = 0; 3 while (true) 4 yield ++i; 5 } 6 7 function* filter(it) { 8 for (var n of it) 9 if (n % 2 == 0) yield curr; 10 } 11 12 function* map(it) { 13 for (var n of it) 14 yield n * n; 15 } 1,2,3,4,5,6
  • 109. 1 function* generateNumber() { 2 var i = 0; 3 while (true) 4 yield ++i; 5 } 6 7 function* filter(it) { 8 for (var n of it) 9 if (n % 2 == 0) yield curr; 10 } 11 12 function* map(it) { 13 for (var n of it) 14 yield n * n; 15 } 1,2,3,4,5,6 n%2 == 0 2,4,6
  • 110. 1 function* generateNumber() { 2 var i = 0; 3 while (true) 4 yield ++i; 5 } 6 7 function* filter(it) { 8 for (var n of it) 9 if (n % 2 == 0) yield curr; 10 } 11 12 function* map(it) { 13 for (var n of it) 14 yield n * n; 15 } 1,2,3,4,5,6 n%2 == 0 2,4,6
  • 111. 1 function* generateNumber() { 2 var i = 0; 3 while (true) 4 yield ++i; 5 } 6 7 function* filter(it) { 8 for (var n of it) 9 if (n % 2 == 0) yield curr; 10 } 11 12 function* map(it) { 13 for (var n of it) 14 yield n * n; 15 } 1,2,3,4,5,6 n%2 == 0 2,4,6 n * n 4,16,36
  • 112. Using the generators 1 var nice = generateNumber(); 2 nice = filter(nice); 3 nice = map(nice); 4 5 for (var i = 0; i < 3; i++) { 6 console.log(i, nice.next().value); 7 }
  • 113. Using the generators 1 var nice = generateNumber(); 2 nice = filter(nice); 3 nice = map(nice); 4 5 for (var i = 0; i < 3; i++) { 6 console.log(i, nice.next().value); 7 }
  • 115. Two way interaction 1 function* printName() { 2 var name = yield 'Whats your name?'; 3 console.log('Hello', name); 4 } 5 6 var iterator = printName(); 7 console.log('It:', iterator.next().value); 8 9 setTimeout(function() { 10 var ret = iterator.next('Jan Jongboom'); 11 console.log(ret); 12 }, 1000);
  • 116. Two way interaction 1 function* printName() { 2 var name = yield 'Whats your name?'; 3 console.log('Hello', name); 4 } 5 6 var iterator = printName(); 7 console.log('It:', iterator.next().value); 8 9 setTimeout(function() { 10 var ret = iterator.next('Jan Jongboom'); 11 console.log(ret); 12 }, 1000);
  • 117. Two way interaction 1 function* printName() { 2 var name = yield 'Whats your name?'; 3 console.log('Hello', name); 4 } 5 6 var iterator = printName(); 7 console.log('It:', iterator.next().value); 8 9 setTimeout(function() { 10 var ret = iterator.next('Jan Jongboom'); 11 console.log(ret); 12 }, 1000);
  • 118. Two way interaction 1 function* printName() { 2 var name = yield 'Whats your name?'; 3 console.log('Hello', name); 4 } 5 6 var iterator = printName(); 7 console.log('It:', iterator.next().value); 8 9 setTimeout(function() { 10 var ret = iterator.next('Jan Jongboom'); 11 console.log(ret); 12 }, 1000);
  • 119. Two way interaction 1 function* printName() { 2 var name = yield 'Whats your name?'; 3 console.log('Hello', name); 4 } 5 6 var iterator = printName(); 7 console.log('It:', iterator.next().value); 8 9 setTimeout(function() { 10 var ret = iterator.next('Jan Jongboom'); 11 console.log(ret); 12 }, 1000);
  • 120. Two way interaction 1 function* printName() { 2 var name = yield 'Whats your name?'; 3 console.log('Hello', name); 4 } 5 6 var iterator = printName(); 7 console.log('It:', iterator.next().value); 8 9 setTimeout(function() { 10 var ret = iterator.next('Jan Jongboom'); 11 console.log(ret); 12 }, 1000);
  • 121. Two way interaction 1 function* printName() { 2 var name = yield 'Whats your name?'; 3 console.log('Hello', name); 4 } 5 6 var iterator = printName(); 7 console.log('It:', iterator.next().value); 8 9 setTimeout(function() { 10 var ret = iterator.next('Jan Jongboom'); 11 console.log(ret); 12 }, 1000); $ node --harmony test.js It: Whats your name?
  • 122. Two way interaction 1 function* printName() { 2 var name = yield 'Whats your name?'; 3 console.log('Hello', name); 4 } 5 6 var iterator = printName(); 7 console.log('It:', iterator.next().value); 8 9 setTimeout(function() { 10 var ret = iterator.next('Jan Jongboom'); 11 console.log(ret); 12 }, 1000); $ node --harmony test.js It: Whats your name? $ node --harmony test.js It: Whats your name? Hello Jan Jongboom { value: undefined, done: true }
  • 123. Yield and deferred values • Wrote sync code • But yield waits until new value comes in... • So it’s actually async with sync syntax • We need to abuse this! 1 function* printName() { 2 var name = yield 'Whats your name?'; 3 console.log('Hello', name); 4 }
  • 124. 1 function* run() { 2 yield sleep(2000); 3 console.log('It has been 2 seconds'); 4 } 5 6 function sleep(ms) { 7 return new Promise((res, rej) => { 8 setTimeout(res, ms); 9 }); 10 } 11 12 var it = run(); 13 var ret = it.next().value; 14 15 ret.then(function() { 16 it.next(); 17 });
  • 125. 1 function* run() { 2 yield sleep(2000); 3 console.log('It has been 2 seconds'); 4 } 5 6 function sleep(ms) { 7 return new Promise((res, rej) => { 8 setTimeout(res, ms); 9 }); 10 } 11 12 var it = run(); 13 var ret = it.next().value; 14 15 ret.then(function() { 16 it.next(); 17 });
  • 126. 1 function* run() { 2 yield sleep(2000); 3 console.log('It has been 2 seconds'); 4 } 5 6 function sleep(ms) { 7 return new Promise((res, rej) => { 8 setTimeout(res, ms); 9 }); 10 } 11 12 var it = run(); 13 var ret = it.next().value; 14 15 ret.then(function() { 16 it.next(); 17 });
  • 127. 1 function* run() { 2 yield sleep(2000); 3 console.log('It has been 2 seconds'); 4 } 5 6 function sleep(ms) { 7 return new Promise((res, rej) => { 8 setTimeout(res, ms); 9 }); 10 } 11 12 var it = run(); 13 var ret = it.next().value; 14 15 ret.then(function() { 16 it.next(); 17 });
  • 128. 1 function* run() { 2 yield sleep(2000); 3 console.log('It has been 2 seconds'); 4 } 5 6 function sleep(ms) { 7 return new Promise((res, rej) => { 8 setTimeout(res, ms); 9 }); 10 } 11 12 var it = run(); 13 var ret = it.next().value; 14 15 ret.then(function() { 16 it.next(); 17 });
  • 129. 1 function* run() { 2 yield sleep(2000); 3 console.log('It has been 2 seconds'); 4 } 5 6 function sleep(ms) { 7 return new Promise((res, rej) => { 8 setTimeout(res, ms); 9 }); 10 } 11 12 var it = run(); 13 var ret = it.next().value; 14 15 ret.then(function() { 16 it.next(); 17 });
  • 130. 1 function* run() { 2 yield sleep(2000); 3 console.log('It has been 2 seconds'); 4 } 5 6 function sleep(ms) { 7 return new Promise((res, rej) => { 8 setTimeout(res, ms); 9 }); 10 } 11 12 var it = run(); 13 var ret = it.next().value; 14 15 ret.then(function() { 16 it.next(); 17 });
  • 131. 1 function* run() { 2 yield sleep(2000); 3 console.log('It has been 2 seconds'); 4 } 5 6 function sleep(ms) { 7 return new Promise((res, rej) => { 8 setTimeout(res, ms); 9 }); 10 } 11 12 var it = run(); 13 var ret = it.next().value; 14 15 ret.then(function() { 16 it.next(); 17 });
  • 132. 1 function* run() { 2 yield sleep(2000); 3 console.log('It has been 2 seconds'); 4 } 5 6 function sleep(ms) { 7 return new Promise((res, rej) => { 8 setTimeout(res, ms); 9 }); 10 } 11 12 var it = run(); 13 var ret = it.next().value; 14 15 ret.then(function() { 16 it.next(); 17 });
  • 133. http://pag.forbeslindesay.co.uk/#/22 1 run(function* () { 2 var data = yield $.get('/yolo'); 3 data = JSON.parse(data); 4 });
  • 134. http://pag.forbeslindesay.co.uk/#/22 1 run(function* () { 2 try { 3 var moar = yield $.post('/other'); 4 } 5 catch (ex) { 6 console.error('Oh noes!', ex); 7 } 8 });
  • 135. http://pag.forbeslindesay.co.uk/#/22 1 run(function* () { 2 var req1 = $.get('http://a'); 3 var req2 = $.get('http://b'); 4 5 $('.status').text( yield req1 + yield req2); 6 });