狠狠撸

狠狠撸Share a Scribd company logo
async awaitでの繰り返し処理
についての小話
2017.1.27
Developers in KOBE Vol. 11
BathTimeFish 村岡 正和
HTML5-WEST.jp代表 / html5j マークアップ部 部長 / HTML5 Experts.jp メンバー
NPO法人日本ウェアラブルデバイスユーザー会理事
神戸市ウェアラブルデバイス推進会議メンバーなど
むらおか まさかず
村岡正和
Webアプリケーション開発 IT業務システム設計/開発
Webサービス導入/事業戦略コンサルティング
神戸デジタル?ラボ 社外取締役
@bathtimefish
HTML5-WEST.jp
英语ができないのに外国で英语プレゼンしてきた件
async / await やってます?
https://tc39.github.io/ecmascript-asyncawait/
babelでstage 3つかってますが
asyncファンクション内で繰り返し処理を
やったとき「あーなるほどなー」って
思ったのでちょっと話します。
Array.forEach をやめて
for … of とか for … in とか使おうぜ
って話です。
具体的には、
とりあえず、検証环境のセットアップ
mkdir async-test && cd $_
npm init
npm i -D babel-cli
npm i -D babel-polyfill
npm i -D babel-preset-es2015
npm i -D babel-preset-stage-3
babelのセットアップ
.babelrcを作成する
{
"presets": [
"es2015",
"stage-3"
]
}
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"
}
検証コード1
forEachで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();
awaitは予約語だと怒られる。
$ babel foreach-not-work.js -o test.js
SyntaxError: 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 | }
なぜか?
Array.forEach() 内のクロージャに
asyncキーワードが影響してない
代替案をさがす
for … of 文
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for...of
検証コード2
for…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();
コンパイルが通った。
$ babel forof-works-good.js -o test.js
$
実行すると怒られた。
$ 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が効いてない感じ。
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のバグ?
とりあえず手で直してみた。(本題とは関係ないので)
'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) {
…(省略)…
実行すると動いた。
$ node test.js
1 times.
2 times.
3 times.
他にも似たような話がissueにあがってました
https://github.com/babel/babel/issues/909
検証コード3
async キーワードをつける
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();
コンパイルが通った。
$ babel foreach-bad-work.js -o test.js
$
実行すると動いた…けどおかしい
$ node test.js
done
1 times.
2 times.
3 times.
Array.forEachが同期してない挙動
ここでもfor…of文推奨のコメントあり
https://github.com/babel/babel/issues/909#issuecomment-76468515
小話まとめ
async function内でawait回すときには
Array.forEach使わないようにしよう
Array.forEachよく考えると例外的に同期処理
だったりbreakできない問題とかあって微妙に
使いどころ考えたりするやつ
配列回すのはもうfor…of一択でよくね?
おまけ
JSにasync/await実装のアイデアはけっこう古い(2012年頃)
http://maxtaco.github.io/coffee-script/
async/awaitに至るまでの実装の経緯を昔話しました。
http://www.slideshare.net/bathtimefish/async-flow-controll-basic-and-practice
Thanks !

More Related Content

Async awaitて?の繰り返し処理についての小話