Async executed code also blocks UI
Talk from Philip Roberts @JSConf EU 2014:
what will I talk about
function doSomething() {
let data = foo();
data = bar(data);
return baz(data);
}
let result = doSomething();
console.log(result);
function doSomething() {
let data = foo();
data = bar(data);
return baz(data);
}
try {
let result = doSomething();
console.log(result);
} catch(err) {
console.error(err);
}
function bar(value) {
console.log(value);
}
function foo(cb) {
setTimeout(function() {
// do some work
cb(2);
}, 0);
}
foo(bar);
console.log(1);
//-> 1
//-> 2
const fs = require('fs');
fs.readFile('./README.md', (err, data) => {
// do some work here
});
const fs = require('fs');
fs.readFile('./README.md', (err, data) => {
if (err) {
// handle error
} else {
// process data
}
});
const fs = require('fs');
try {
fs.readFile('./README.md', (err, data) => {
if (err) {
throw err;
}
console.log('done');
});
} catch(err) {
console.error(err);
}
function doSomething(cb) {
foo((err, data) => {
bar(data, (err, data) => {
baz(data, cb);
});
});
}
doSomething((err, data) => {
console.log(data);
});
function doSomething(cb) {
foo((err, data) => {
if (err) {
cb(err);
} else {
bar(data, (err, data) => {
if (err) {
cb(err);
} else {
baz(data, cb);
}
});
}
});
}
doSomething((err, data) => {
if (err) {
console.error(err);
} else {
console.log(data);
}
});
function doSomething(cb) {
foo((err, data) => {
if (err) {
return cb(err);
}
bar(data, (err, data) => {
if (err) {
return cb(err);
}
baz(data, cb);
});
});
}
doSomething((err, data) => {
if (err) {
return console.error(err);
}
console.log(data);
});
function doSomething(cb) {
foo((err, data) => {
if (err) {
return cb(err);
}
bar(data, (err, data) => {
if (err) {
return cb(err);
}
baz(data, cb);
});
});
}
doSomething((err, data) => {
if (err) {
return console.error(err);
}
console.log(data);
});
function doSomething() {
let data = foo();
data = bar(data);
return baz(data);
}
try {
let result = doSomething();
console.log(result);
} catch(err) {
console.error(err);
}
new Promise(function(resolve, reject) { ... } );
pending := !fulfilled && !rejected
fulfilled
rejected
new Promise((resolve, reject) => {
// executes immediatly
// do some work
// pending state
if (foo) {
resolve(foo);
// fulfilled state
} else {
reject(reason);
// rejected state
}
});
Promise.reject('reason');
// state rejected
Promise.resolve('value');
// state fulfilled
Promise.resolve(Promise.reject('reason'));
// return passed Promise, state rejected
Promise.all([
Promise.resolve('val1'),
Promise.resolve('val2')
]); // resolves async, state pending, will fulfill
Promise.all([]); // resolves sync, state fulfilled
Promise.all([
'val1',
'val2'
]); // resolves async (sync on Chrome 58), state pending (fulfilled), will fulfill
Promise.all([
Promise.resolve('value'),
Promise.reject('reason')
]); // resolves sync, state rejected
Promise.race([
Promise.resolve('val1'),
Promise.reject('val2')
]); // state pending, will fulfill with value: 'val1'
Promise.race([
Promise.reject('val2'),
Promise.resolve('val1')
]); // state pending, will reject with reason: 'val2'
Promise.race([]); // will pending forever
Promise.prototype.then(onFulfilled[, onRejected]);
Promise.resolve('value').then((data) => {
console.log(data);
});
Promise.reject('reason').then((data) => {},
(reason) => {
console.error(reason);
});
Promise.prototype.catch(onRejected);
Promise.reject('reason').catch((reason) => {
console.error(reason);
});
let promise = Promise.reject(Error('test'));
// -> Uncaught (in promise) Error: test
let promise = Promise.reject(Error('test'));
promise.catch((error) => {
// handle error
});
// -> No output
let promise = Promise.reject(Error('test'));
promise.catch((error) => {
// handle error
});
promise.then((value) => {
// will never executed
});
// -> Uncaught (in promise) Error: test
let promise = Promise.reject(Error('test'));
promise.catch((error) => {
// handle error
});
promise.then((value) => {
// will never executed
}, (err) => {});
promise.then((value) => {
// will never executed
}).catch((err) => {});
// -> No output
let promise = Promise.resolve({ name: 'Andreas'});
promise.then((value) => {
console.log('1: '+value.name);
value.name = 'Andi';
return value;
}).then((value) => {
console.log('2: '+value.name);
});
// -> 1: Andreas
// -> 2: Andy
let promise = Promise.resolve({ name: 'Andreas'});
promise.then((value) => {
console.log('1: '+value.name);
value.name = 'Andi';
return value;
}).then((value) => {
console.log('2: '+value.name);
});
// ....
promise.then((value) => {
console.log('1.5: '+value.name);
value.name = 'Andy';
});
// -> 1: Andreas
// -> 1.5: Andi
// -> 2: Andy
Promise.resolve().then((data) => {
return Promise.resolve('data');
}).then((data) => {
console.log(data); // -> 'data'
return 42;
}).then(undefined, (error) => {
// this will never been reached
}).then((data) => {
console.log(data); // -> 42
throw Error('message');
}).then((data) => {
// this will never been reached
}).catch((error) => {
// handle error;
});
function doSomething() {
return Promise.resolve(foo())
.then((data) => {
return bar(data);
})
.then((data) => {
return baz(data);
});
}
doSomething().then((data) => {
console.log(data);
}).catch((error) => {
console.error(error);
});
function doSomething() {
return Promise.resolve()
.then(foo)
.then(bar)
.then(baz);
}
doSomething().then((data) => {
console.log(data);
}).catch((error) => {
console.error(error);
});
function doSomething() {
return Promise.resolve()
.then(foo)
.then(bar)
.then(baz);
}
doSomething().then((data) => {
console.log(data);
}).catch((error) =>
console.error(error);
});
function doSomething() {
let data = foo();
data = bar(data);
return baz(data);
}
try {
let result = doSomething();
console.log(result);
} catch(err) {
console.error(err);
}
async function
-declarationawait
operatorasync function foo() {
return 'value';
return Promise.resolve('value');
return Promise.reject(Error('reason'));
throw Error('reason');
await Promise.reject(Error('reason'));
}
let fooPromise = foo();
async function foo() {
try {
let value = await Promise.resolve('value');
await Promise.reject(Error('reason'));
// never reached
return value;
} catch(error) {
// handle error
// return fallbackValue;
// or
// throw error;
}
...
}
async function doSomething() {
let data = await foo();
data = await bar(data);
return await baz(data);
}
doSomething().then((data) => {
console.log(data);
}).catch((error) =>
console.error(error);
});
function doSomething() {
let data = foo();
data = bar(data);
return baz(data);
}
try {
let result = doSomething();
console.log(result);
} catch(err) {
console.error(err);
}
parallel execution
async function () {
let promA = new Promise(...);
let promB = new Promise(...);
return await promA + await promB;
}
async function () {
let [resultA, resultB] = await Promise.all([
new Promise(...),
new Promise(...)
]);
return resultA + resultBB;
}
function* genFunc([param[, ... param]]) { statements }
let genObj = genFunc();
Generator.prototype.next()
Generator.prototype.return()
Generator.prototype.throw()
function* fibonacci() {
let current = 0;
let next = 1;
while (true) {
yield current;
[current, next] = [next, current + next];
}
}
let sequence = fibonacci();
console.log(sequence.next()); // { done: false, value: 0}
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 2
function* fibonacci() {
let reset = true, current, next;
while (true) {
if (reset){
current = 0;
next = 1;
}
reset = yield current;
[current, next] = [next, current + next];
}
}
let sequence = fibonacci();
console.log(sequence.next()); // { done: false, value: 0}
console.log(sequence.next().value); // 1
console.log(sequence.next().value); // 1
console.log(sequence.next(true).value); // 0
function* gen() {
yield 1;
yield 2;
yield 3;
}
var g = gen();
g.next(); // { value: 1, done: false }
g.return(); // { value: undefined, done: true }
g.return('foo'); // { value: "foo", done: true }
g.next(); // { value: undefined, done: true }
function* gen() {
while(true) {
try {
yield 42;
} catch(e) {
console.log('Error caught!');
}
}
}
var g = gen();
g.next();
// { value: 42, done: false }
g.throw(new Error('Something went wrong'));
// "Error caught!"
// { value: 42, done: false }
let runGenerator = function(generatorFunction) {
// recursive next()
let next = function (arg) {
let result = it.next(arg);
// are we done?
if (result.done) return;
if (typeof result.value == 'function') {
result.value(next);
}
else {
// if the response isn't a function, pass it to next()
next(result.value);
}
}
// create the iterator
let it = generatorFunction();
return next();
}
// initiliase and pass in a generator function
runGenerator(function* () {
let val = yield fetch(url);
let val2 = yield fetch(url2);
});
export default Ember.Component.extend({
result: null,
actions: {
async getProducts() {
let products = await this.get('store').get('products');
this.set('result', products);
}
},
});
export default Ember.Component.extend({
result: null,
fetching: false,
actions: {
async getProducts() {
if (this.get('fetching')) { return; }
this.set('fetching', true);
try {
let products = await this.get('store').get('products');
if (this.get('isDestroyed')) { return; }
this.set('result', products);
} finally (err) {
if (this.get('isDestroyed')) { return; }
this.set('fetching', false);
}
}
},
});
export default Ember.Component.extend({
result: null,
getProducts: task(function* () {
let products = yield this.get('store').get('products');
this.set('result', product);
}).drop()
});