async&generators& - es discuss generators.pdfa&ques
TRANSCRIPT
![Page 1: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/1.jpg)
Async Generators
Composable Async Programming in ES7
![Page 2: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/2.jpg)
ES6 has Generator Func<ons function *numbers() { let file = new FileReader(“numbers.txt”); try { while(!file.eof) { yield parseInt(file.readLine(), 10);
} } finally { file.close(); }
}
![Page 3: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/3.jpg)
Async Func<ons are proposed for ES7
async function getStockPrice(symbol, currency) { let price = await getStockPrice(symbol); return convert(price, currency);
}
![Page 4: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/4.jpg)
A Ques<on that needs Answering
If an async func<on returns a Promise, and a generator func<on returns an Iterator…
![Page 5: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/5.jpg)
A Ques<on that needs Answering
…what does an async generator func<on return?
async function*() -‐> ?
![Page 6: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/6.jpg)
A Ques<on that needs Answering
Synchronous Asynchronous
func<on T Promise
func<on* Iterator ???
![Page 7: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/7.jpg)
async func<on*() -‐> ?
An async func<on sends a value using a callback.
A generator func<ons yields mul<ple values, and terminates with a return value or an error.
![Page 8: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/8.jpg)
async func<on*
An async generator func<on sends mul<ple values using callbacks, and terminates with a
return value or an error.
![Page 9: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/9.jpg)
async func<on*() -‐> ?
Promise<Iterable<T>> ?
![Page 10: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/10.jpg)
async func<on*() -‐> ?
Iterable<Promise<T>> ?
![Page 11: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/11.jpg)
Why?
• Absence creates refactoring hazard • Support asynchronous stream composi<on – Events for web developers – Async IO for server developers
• Support pending features in ES7 and web plaRorm
• Validate generator and async func<on design
![Page 12: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/12.jpg)
Event Composi<on async function *getDrags(element) { for(let mouseDown on element.mouseDowns) { for(let mouseMove on document.mouseMoves. takeUntil(document.mouseUps)) { yield mouseMove; } }
}
![Page 13: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/13.jpg)
Sync IO with func<on* function* getStocks() {
let reader = new FileReader(“stocks.txt”); try { while(!reader.eof) { let line = reader.readLine(); yield JSON.parse(line);
} } finally { reader.close(); }
} function writeStockInfos() {
let writer = new FileWriter(“stocksAndPrices.txt”); try { for(let name of getStocks()) { let price = getStockPrice(name); writer.writeLine(JSON.stringify({name, price})); } } finally { writer.close(); }
}
![Page 14: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/14.jpg)
Async IO with async func<on* async function* getStocks() {
let reader = new AsyncFileReader(“stocks.txt”); try { while(!reader.eof) { let line = await reader.readLine(); await yield JSON.parse(line);
} } finally { reader.close(); }
} async function writeStockInfos() {
let writer = new AsyncFileWriter(“stocksAndPrices.txt”); try { for(let name on getStocks()) { let price = await getStockPrice(name); await writer.writeLine(JSON.stringify({name, price})); } } finally { writer.close(); }
}
![Page 15: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/15.jpg)
How does this work?
Itera<on and Observa<on are symmetrical.
![Page 16: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/16.jpg)
Itera<on and Observa<on
• Share the same seman<cs • Can be created/consumed using same syntax and control structures
• Can be composed using the same operators
![Page 17: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/17.jpg)
Top-‐rated Movies Collec<on let getTopRatedFilms = user => user.genreLists. flatMap(genreList => genreList.videos. filter(video => video.rating === 5.0)); getTopRatedFilms(user). forEach(film => console.log(film));
![Page 18: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/18.jpg)
Mouse Drags Collec<on let getElementDrags = elmt => elmt.mouseDowns. flatMap(mouseDown => elmt.mouseMoves. filter takeUntil(elmt.mouseUps)); getElementDrags(image). forEach(pos => moveTo(image, pos));
![Page 19: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/19.jpg)
Itera<on and Observa<on
The only difference is which party is in control, the consumer or the producer.
![Page 20: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/20.jpg)
Generator Func<on is Itera<on
Producer sends the consumer a generator, and the consumer uses it as a data source.
Consumer Pulls Data
![Page 21: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/21.jpg)
A Generator is a Data Source
• Can yield data – generator.next().value;
• Can throw an error and terminate – try { generator.next(); } catch(e) { log(‘error’,e); }
• Can return a value and terminate – if ((pair = generator.next()).done === true) log(pair.value);
![Page 22: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/22.jpg)
Async Generator Func<on is Observa<on
Producer receives generator from consumer, and the producer uses it as a data sink.
Data Pushed To Consumer
![Page 23: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/23.jpg)
A Generator is a Data Sink
• Can receive data – generator.next(44);
• Can receive an error and terminate – generator.throw(“The operation did not succeed”);
• Can receive a return value and terminate – generator.return(5);
![Page 24: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/24.jpg)
What does an async generator func<on return?
![Page 25: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/25.jpg)
Introducing Observable let nums = async function*() {
yield 1; yield 2; return 3;
} let numbers = nums(); // returns Observable numbers.
observe({ next(v) { if (v === 1) { return {done: true}; } }, throw(e) { log.error(e); }, return(v) { log(v); } });
“Pushes” data to consumer
Consumer can short-‐circuit
![Page 26: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/26.jpg)
interface Iterable { Generator iterator(void);
}
Introducing Observable
interface Observable { void observe(Generator);
}
![Page 27: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/27.jpg)
How to short-‐circuit? let nums = async function*() {
yield 1; yield 2; return 3;
} let numbers = nums(); // returns Observable numbers.
observe({ next(v) { if (v === 1) { return {done: true}; } }, throw(e) { log.error(e); } return(v) { log(v); } });
Ques<on If the producer is in control, how can the consumer short-‐circuit without first ge]ng a no<fica<on?
![Page 28: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/28.jpg)
Short-‐circui<ng Async Func<ons
interface Observable { void observe(Generator); }
interface Observable { void Generator observe(Generator); }
interface Observable { Generator observe(Generator); }
![Page 29: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/29.jpg)
Detec<ng consumer short-‐circuit
• Producer adds new object to generator prototype chain
• Decorates throw and return methods • Intercepts calls to detect consumer short-‐circuit
![Page 30: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/30.jpg)
$decorateGenerator function $decorateGenerator(generator, onDone) {
let throwFn = generator.throw, returnFn = generator.return;
return Object.create( generator, { throw: { value: function(e) { onDone(); if (throwFn) { throwFn.call(generator, e); } } }, return { value: function(v) { onDone(); if (returnFn) { returnFn.call(generator, v); } } } });
}
![Page 31: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/31.jpg)
Short-‐circui<ng Async Gen Func<on let nums = async function*() {
yield 1; yield 2; return 3;
} let decoratedIterator =
nums(). observe({ next(v) { log(v); }, throw(e) { log.error(e); } return(v) { log(v); } });
// consumer can asynchronously short-‐circuit decoratedIterator.return();
![Page 32: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/32.jpg)
Async Generators Desugared async function *nums() {
yield 1; yield 2; return 3;
}
function nums() {
return new Observable(generator => { let done = false, decoratedIterator =
$decorateGenerator( generator, function onDone() { done = true; }),
next = generator.next;
async function() { try { if (done) return;
decoratedIterator.next(1); if (done) return; decoratedIterator.next(2);
if (done) return; decoratedIterator.return(3);
} catch(e) { if (decoratedIterator.throw) decoratedIterator.throw(e) } }();
return decoratedIterator; });
}
![Page 33: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/33.jpg)
Object.observe as an async generator Object.observations = function(obj) {
return new Observable(generator => { let next = generator.next, decoratedIterator = $decorateGenerator(generator, unobserve), handler = ev => { if (next) { next.call(decoratedIterator, ev); } }, unobserve = () => Object.unobserve(obj, handler); Object.observe(obj, handler);
return decoratedIterator; });
};
![Page 34: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/34.jpg)
Generator Func<on let numbers = function*() { let file = new FileReader(“numbers.txt”); try { while(!file.eof) { yield parseInt(file.readLine(), 10);
} } finally { file.close(); }
}
![Page 35: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/35.jpg)
Async Generator Func<on let numbers = async function*() { let file = new AsyncFileReader(“numbers.txt”); try { while(!file.eof) { yield parseInt(await file.readLine(), 10);
} } finally { file.close(); }
}
![Page 36: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/36.jpg)
for…of
function writeNums() { let sum = 0; for(let x of numbers()) { sum += x; } return sum;
}
![Page 37: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/37.jpg)
for…on
async function writeNums() { let sum = 0; for(let x on numbers()) { sum += x; } return sum;
}
![Page 38: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/38.jpg)
for…on desugared
async function writeNums() { try { for(let x on numbers()) { log(x); } log(“completed”); } catch(e) { log(“error:”, e); }
}
function writeNums() return numbers(). forEach(x => log(x)). then( () => log(“completed”), e => { log(“error:, e); });
}
![Page 39: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/39.jpg)
Observable.forEach Observable.prototype.forEach = function(next) { return new Promise((accept, reject) => { return this.observe({ next, throw: reject, return: accept }) });
}
![Page 40: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/40.jpg)
An Answer to the Ques<on
Synchronous Asynchronous
func<on T Promise<T>
Generator func<on Iterator<T> Observable<T>
![Page 41: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/41.jpg)
Observable Methods
• All applicable array methods • retry() • takeUn<l() • Varia<ons of flatMap – mergeMap() – concatMap() – switchMap()
![Page 42: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/42.jpg)
Auto-‐complete
var searchResultSets = keyPresses. mergeMap(key => getJSON(“/searchResults?q=” + input.value). retry(3). takeUntil(keyPresses)); searchResultSets.forEach( resultSet => updateSearchResults(resultSet));
![Page 43: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/43.jpg)
Nes<ng await expression in for…on
async function *getStockInfos() { for(let stock on stocks()) { let price = await getPrice(stock); yield {name: stock.name, price}; }
}
Should observa<on pause while awai<ng promise?
![Page 44: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/44.jpg)
Should observa<on pause for await?
Yes.
“Wait” is the opera<ve word.
![Page 45: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/45.jpg)
Ques<on
How do we pause Observa<on un<l an async opera<on completes?
![Page 46: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/46.jpg)
Ques<on
How do we pause Observa<on Itera<on un<l an async opera<on completes?
![Page 47: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/47.jpg)
Task.js spawn(function*() { var data = yield $.ajax(url);
$('#result').html(data); var status = $('#status').html('Download complete.');
yield status.fadeIn().promise(); yield sleep(2000); status.fadeOut(); });
![Page 48: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/48.jpg)
Ques<on
How do we pause Observa<on un<l an async opera<on completes?
![Page 49: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/49.jpg)
Nes<ng await and for…on
async function *getStockInfos() { for(let stock on stocks()) { let price = await getPrice(stock); yield {name: stock.name, price}; }
}
![Page 50: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/50.jpg)
Pausing Observa<on
Producer Consumer
Pulls promise
Wait un<l promise fulfilled
Push value
Pulls promise Push value
![Page 51: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/51.jpg)
Pause Observa<on while Awaiting async function *getStockInfos() {
return new Observable(generator => { let done, decoratedIterator = $decorateGenerator( generator, () => {done = true;});
(async function() { try { await stocks(). forEach(async function(name) { let price = await getPrice(name); if (!done) decoratedIterator.next({name, price}); }); } catch(e) { decoratedIterator.throw(e); } }());
return decoratedIterator; });
}
forEach block returns promise sub-‐expression from next(). Producer yield expression replaced by promise.
![Page 52: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/52.jpg)
Async Generator async function *getStocks() { let file = new AsyncFileReader(“stocks.txt”); try { while(!file.eof) {
let line = await file.readLine(); yield line;
} } finally { file.close(); }
}
![Page 53: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/53.jpg)
Async Generator that Pauses async function *getStocks() { let file = new AsyncFileReader(“stocks.txt”); try { while(!file.eof) {
let line = await file.readLine(); await yield line;
} } finally { file.close(); }
}
Result of yield is a promise! Await result before con<nuing Itera<on.
![Page 54: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/54.jpg)
Async IO with async func<on* async function* getStocks() {
let reader = new AsyncFileReader(“stocks.txt”); try { while(!reader.eof) { let line = await reader.readLine(); await yield JSON.parse(line);
} } finally { reader.close(); }
} async function writeStockInfos() {
let writer = new AsyncFileWriter(“stocksAndPrices.txt”); try { for(let name on getStocks()) { let price = await getStockPrice(name); await writer.writeLine(JSON.stringify({name, price})); } } finally { writer.close(); }
}
![Page 55: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/55.jpg)
ES7 Comprehensions async function writeStockInfos() {
var stocks = (for (stock from PausableObservable.from(getStocks())) for (price from PausableObservable.from(getPrice(stock))) { stock, price }); let writer = new AsyncFileWriter(“stocksAndPrices.txt”); try { for(let name on stocks) { let price = await getStockPrice(name); await writer.writeLine(JSON.stringify({name, price})); } } finally { writer.close(); }
}
![Page 56: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/56.jpg)
ES7 Comprehensions
var stocks = (for (stock from PausableObservable.from(getStocks())) for (price from PausableObservable.from(getPrice(stock))) { stock, price });
var stocks =
PausableObservable. from(getStocks()). mergeMap(stock => PausableObservable. from(getPrice(stock)). map(price => { stock, price }));
![Page 57: Async&Generators& - ES Discuss generators.pdfA&Ques](https://reader034.vdocuments.us/reader034/viewer/2022050115/5f4bebce5664c946a8424a35/html5/thumbnails/57.jpg)
Valida<ng Promises, async/await
• await should mirror then and condi<onally unwrap
• Inability to cancel Promises causes fric<on • Turning async generator into Promise loses cancella<on seman<cs