async awaitでの繰り返し処理についての小話

31
async await でででででででで ででででででで 2017.1.27 Developers in KOBE Vol. 11 BathTimeFish でで でで

Upload: masakazu-muraoka

Post on 07-Feb-2017

154 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Async awaitでの繰り返し処理についての小話

async await での繰り返し処理についての小話

2017.1.27Developers in KOBE Vol. 11

BathTimeFish 村岡 正和

Page 2: Async awaitでの繰り返し処理についての小話

HTML5-WEST.jp 代表 / html5j マークアップ部 部長 / HTML5 Experts.jp メンバーNPO 法人日本ウェアラブルデバイスユーザー会理事神戸市ウェアラブルデバイス推進会議メンバーなど

むらおか まさかず

村岡正和Web アプリケーション開発  IT 業務システム設計 / 開発

Web サービス導入 / 事業戦略コンサルティング神戸デジタル・ラボ 社外取締役

@bathtimefish

HTML5-WEST.jp

Page 3: Async awaitでの繰り返し処理についての小話

英語ができないのに外国で英語プレゼンしてきた件

Page 4: Async awaitでの繰り返し処理についての小話

async / await やってます?

https://tc39.github.io/ecmascript-asyncawait/

Page 5: Async awaitでの繰り返し処理についての小話

babel で stage 3 つかってますが

async ファンクション内で繰り返し処理をやったとき「あーなるほどなー」って

思ったのでちょっと話します。

Page 6: Async awaitでの繰り返し処理についての小話

Array.forEach をやめてfor … of とか for … in とか使おうぜ

って話です。

具体的には、

Page 7: Async awaitでの繰り返し処理についての小話

とりあえず、検証環境のセットアップ

Page 8: Async awaitでの繰り返し処理についての小話

mkdir async-test && cd $_npm initnpm i -D babel-clinpm i -D babel-polyfillnpm i -D babel-preset-es2015npm i -D babel-preset-stage-3

babel のセットアップ

Page 9: Async awaitでの繰り返し処理についての小話

.babelrc を作成する

{ "presets": [ "es2015", "stage-3" ]}

Page 10: Async awaitでの繰り返し処理についての小話

package.jsop のようす

"devDependencies": { "babel-cli": "^6.22.2”, "babel-polyfill": "^6.22.0" "babel-preset-es2015": "^6.22.0", "babel-preset-stage-3": "^6.22.0" }

Page 11: Async awaitでの繰り返し処理についての小話

検証コード 1forEach で await を繰り返す

import 'babel-polyfill';

function sleep(count) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(count); }, count*1000); });}

async function Main() { let times = [1, 2, 3]; times.forEach((t) => { let time = await sleep(t); console.log(time.toString() + ' times.'); });}

Main();

Page 12: Async awaitでの繰り返し処理についての小話

await は予約語だと怒られる。

$ babel foreach-not-work.js -o test.jsSyntaxError: foreach-not-work.js: await is a reserved word (14:15) 12 | let times = [1, 2, 3]; 13 | times.forEach((t) => {> 14 | let time = await sleep(t); | ^ 15 | console.log(time.toString() + ' times.'); 16 | }) 17 | }

Page 13: Async awaitでの繰り返し処理についての小話

なぜか?

Array.forEach() 内のクロージャにasync キーワードが影響してない

Page 14: Async awaitでの繰り返し処理についての小話

代替案をさがす

Page 15: Async awaitでの繰り返し処理についての小話

for … of 文

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for...of

Page 16: Async awaitでの繰り返し処理についての小話

検証コード 2for…of で await を繰り返す

import 'babel-polyfill';

function sleep(count) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(count); }, count*1000); });}

async function Main() { let times = [1, 2, 3]; for (let t of times) { let time = await sleep(t); console.log(time.toString() + ' times.'); }}

Main();

Page 17: Async awaitでの繰り返し処理についての小話

コンパイルが通った。

$ babel forof-works-good.js -o test.js$

Page 18: Async awaitでの繰り返し処理についての小話

実行すると怒られた。$ node test.js/Users/btf/src/node.js/async-await-for/test.js:4 var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() { ^

ReferenceError: regeneratorRuntime is not defined at /Users/btf/src/node.js/async-await-for/test.js:4:32 at Object.<anonymous> (/Users/btf/src/node.js/async-await-for/test.js:83:2) at Module._compile (module.js:571:32) at Object.Module._extensions..js (module.js:580:10) at Module.load (module.js:488:32) at tryModuleLoad (module.js:447:12) at Function.Module._load (module.js:439:3) at Module.runMain (module.js:605:10) at run (bootstrap_node.js:420:7) at startup (bootstrap_node.js:139:9)

ぐぐってみると babel-polyfill が効いてない感じ。

Page 19: Async awaitでの繰り返し処理についての小話

test.js を開いてみる

'use strict';

var Main = function () { var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() { var times, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, t, time;

return regeneratorRuntime.wrap(function _callee$(_context) {

…( 中略 )…

require('babel-polyfill');

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if

Main() の後に babel-polyfill を呼んでる。なんで? babel のバグ?

Page 20: Async awaitでの繰り返し処理についての小話

とりあえず手で直してみた。(本題とは関係ないので)

'use strict';

require('babel-polyfill');

var Main = function () { var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee() { var times, _iteratorNormalCompletion, _didIteratorError, _iteratorError, _iterator, _step, t, time;

return regeneratorRuntime.wrap(function _callee$(_context) {

…( 省略 )…

Page 21: Async awaitでの繰り返し処理についての小話

実行すると動いた。

$ node test.js1 times.2 times.3 times.

Page 22: Async awaitでの繰り返し処理についての小話

他にも似たような話が issue にあがってましたhttps://github.com/babel/babel/issues/909

Page 23: Async awaitでの繰り返し処理についての小話

検証コード 3async キーワードをつける

import 'babel-polyfill';

function sleep(count) { return new Promise((resolve, reject) => { setTimeout(() => { resolve(count); }, count*1000); });}

async function Main() { let times = [1, 2, 3]; times.forEach( async (t) => { let time = await sleep(t); console.log(time.toString() + ' times.'); }); console.log(‘done’);}

Main();

Page 24: Async awaitでの繰り返し処理についての小話

コンパイルが通った。

$ babel foreach-bad-work.js -o test.js$

Page 25: Async awaitでの繰り返し処理についての小話

実行すると動いた…けどおかしい

$ node test.jsdone1 times.2 times.3 times.

Array.forEach が同期してない挙動

Page 26: Async awaitでの繰り返し処理についての小話

ここでも for…of 文推奨のコメントありhttps://github.com/babel/babel/issues/909#issuecomment-76468515

Page 27: Async awaitでの繰り返し処理についての小話

小話まとめ

async function 内で await 回すときにはArray.forEach 使わないようにしようArray.forEach よく考えると例外的に同期処理だったり break できない問題とかあって微妙に使いどころ考えたりするやつ

配列回すのはもう for…of 一択でよくね?

Page 28: Async awaitでの繰り返し処理についての小話

おまけ

Page 29: Async awaitでの繰り返し処理についての小話

JS に async/await 実装のアイデアはけっこう古い (2012 年頃 )

http://maxtaco.github.io/coffee-script/

Page 30: Async awaitでの繰り返し処理についての小話

async/await に至るまでの実装の経緯を昔話しました。http://www.slideshare.net/bathtimefish/async-flow-controll-basic-and-practice

Page 31: Async awaitでの繰り返し処理についての小話

Thanks !