91
JavaScript 非非非非非 非非 非非非非非非非非非非非

JavaScript非同期処理 入門

Embed Size (px)

Citation preview

Page 1: JavaScript非同期処理 入門

JavaScript非同期処理 入門をド素人がお送りします

Page 2: JavaScript非同期処理 入門

自己紹介 (1/2)

• 呼び名は?• まっぴー (@mpyw)• CertaiN ( 技術系で使ってたけど最近 mpyw に統一された )• 小南響くん (@DJ_Komachi) とは何の関係ありません

• 趣味は?• Ingress / osu! / FPS ( 最近全部サボってる )

• Qiita おじさん / 知恵袋おじさん• 学園系アニメ見てニヤニヤする• 嫁の抱き枕ペロペロして妄想に浸る

• どこ研?何やってるの?• ( マイナーな方の ) 伊藤嘉研• ネットワーク全般• 自分の研究は RTP プロトコル関連

Page 3: JavaScript非同期処理 入門

自己紹介 (2/2)

• 今までの実績は?• PHP 製 TwitterAPI ライブラリ – UltimateOAuth• PHP 製 TwitterAPI ライブラリ ( 改良版 ) – TwistOAuth• JavaScript 製 Chrome 用 Twitter 公式 Web

正規表現ミュートプラグイン – TwitterCustomizedMuting• PHP 製ガラケー向け TwitterWeb アプリ – GalaTwi• seccamp 2014 web • pixiv summer internship 2014 engineer• 知恵袋回答数 4500 件 BA 率 73%• Qiita 6000 Contribution

• JavaScript できるの?• できません• PHP は好きです (Web ページを作るとは言ってない )

リポジトリ消滅

閉鎖行っただけ

行っただけ暇人

炎上しただけ

Page 4: JavaScript非同期処理 入門

アジェンダ1. JavaScript の特徴2. Callback パターンの欠点3. Promise を理解する ( 難しいので途中まで )

4. Promise の使い方を覚える1. ECMAScript 6 の Promise2. jQuery.Deferred

5. おまけ1. ECMAScript 6 と ECMAScript 7 のこれから

Page 5: JavaScript非同期処理 入門

1. JavaScript の特徴

Page 6: JavaScript非同期処理 入門

JavaScript の特徴って?• ブラウザ上で動作する• サーバ上でも動作する (node.js)• Alt-JS (CoffeeScript, TypeScript) からコンパイルされて

アセンブリ言語のように使用されることが多い• 変数宣言する際に var が必要

( 付けなければグローバル変数になってしまう )• プロトタイプベースのオブジェクト指向 ( クラスが無

い )• 非同期処理がメイン

    など…

Page 7: JavaScript非同期処理 入門

非同期処理ってつまり…?• 同期処理の場合…

 「ある行の処理を開始後、完結してから次の行に移る」

• 非同期処理の場合… 「ある行の処理を開始後、直ちに次の行に移る」

func : 実行するクロージャ ( 関数オブジェクト )delay : 遅延させるミリ秒時間

delay ミリ秒後に func を実行するのを予約する ( イベントキューに入れる ) ⇛ 予約自体は一瞬で終わる!

window.setTimeout(func, delay)

Page 8: JavaScript非同期処理 入門

setTimeout の使用例

setTimeout(function () { console.log('A');}, 20);console.log('B');setTimeout(function () { console.log('C');}, 0);console.log('D');

B D C A⇛ ⇛ ⇛

0 ミリ秒の遅延 ⇛ イベントキューに追加 ⇛ 出来るだけ早く 実行 ( すぐに実行するとは言ってない )

どの順番で表示される? 答えは…?

Page 9: JavaScript非同期処理 入門

XMLHttpRequest の使用例• XMLHttpRequest って何?• 非同期で通信するためのオブジェクト ( ここではより簡便な LEVEL2 を扱います )

var xhr = new XMLHttpRequest();xhr.open('GET', '/contents.html');xhr.onload = function () { console.log(xhr.response);};xhr.onerror = function () { console.error(xhr.response);};xhr.send(null);

1. インスタンス生成2. /contents.html に GET で

アクセスすることを設定3. 正常完了時のイベントを設定4. エラー時のイベントを設定5. いざ実行開始!

・この行は一瞬で終わる・リクエスト処理は イベントキューに入る

Page 10: JavaScript非同期処理 入門

jQuery.ajax の使用例• jQuery って何?• 標準の JavaScript をより便利にするライブラリ• 「 jQuery 」は「 $ 」とも書ける

• jQuery.ajax って何?• XMLHttpRequest を簡便に書くためのメソッド

$.ajax({ type: 'GET', url: '/contents.html', success: function (data) { console.log(data); }, error: function (xhr) { console.error(xhr.response); }});

• 変数を作る必要がない!• 見やすい!• これで完璧だぜ!

Page 11: JavaScript非同期処理 入門

2. Callback パターンの欠点

Page 12: JavaScript非同期処理 入門

ところで Callback って何?• Wikipedia より…• コールバック(英 : Callback )とは、プログラミングにおい

て、他のコードの引数として渡されるサブルーチンである。 これにより、低レベルの抽象化層が高レベルの層で定義されたサブルーチン(または関数)を呼び出せるようになる。

• つまり JavaScript だと?var xhr = new XMLHttpRequest();xhr.open('GET', '/contents.html');xhr.onload = function () { console.log(xhr.response);};xhr.onerror = function () { console.error(xhr.response);};xhr.send(null);

$.ajax({ type: 'GET', url: '/contents.html', success: function (data) { console.log(data); }, error: function (xhr) { console.error(xhr.response); }});

var xhr = new XMLHttpRequest();xhr.open('GET', '/contents.html');xhr.onload = function () { console.log(xhr.response);};xhr.onerror = function () { console.error(xhr.response);};xhr.send(null);

$.ajax({ type: 'GET', url: '/contents.html', success: function (data) { console.log(data); }, error: function (xhr) { console.error(xhr.response); }});

Page 13: JavaScript非同期処理 入門

Callback のネスト• 例 : もし Aへのリクエストが成功したら、

続けて Bへのリクエストも実行する。 更に Bへのリクエストが成功したら、 「 OK! 」 とログに出す。

$.ajax({ type: 'GET', url: A, success: function () { $.ajax({ type: 'GET', url: B, success: function () { console.log('OK!'); } }); }});

新しい書き方

$.ajax({ type: 'GET', url: A}).then(function () { return $.ajax({ type: 'GET', url: B, });}).then(function () { console.log('OK!');});

Page 14: JavaScript非同期処理 入門

3. Promise を理解する

Page 15: JavaScript非同期処理 入門

Promise って何?• またまた Wikipedia より…• プログラミング言語における並列処理のデザインパターン。何

らかの処理を別のスレッドで処理させる際、その処理結果の取得を必要になるところまで後回しにする手法。処理をパイプライン化させる。

※ JavaScript はシングルスレッドだが、イベントキューを使う ことにより擬似的にマルチスレッドのようなものを実現して いる。

Page 16: JavaScript非同期処理 入門

Promise の理解ぼく「ぼく JS初心者だしなぁ…絶対グダるよなぁ…」  「どうやったらまともな説明出来るかなぁ…」

ぼく「そうだ!あのサイト読み上げればいいんだ!」

↑ ご自身のスマホやタブレットで開いてください

※ 「 3. プロミスは状態を持っている」までを予定

JavaScript Promise ... イカした詳細http://p-baleine.hatenablog.com/entry/2014/03/12/190000

Page 17: JavaScript非同期処理 入門

こ こ か ら が 本 番

Page 18: JavaScript非同期処理 入門

• $.ajax でも出てきたけど…

【コード】  { A: 'foo', B: 'bar' } 【意味】プロパティ A として 'foo'プロパティ B として 'bar' を持つ基本オブジェクト( Java でいうと Object クラスのインスタンス)

2-1. シンプルなユースケース

Page 19: JavaScript非同期処理 入門

2-1. シンプルなユースケースdoSomething().then(function(value) { console.log('Got a value' + value);});

function doSomething() { return { then: function (callback) { var value = 42; callback(value); } };}

Page 20: JavaScript非同期処理 入門

2-1. シンプルなユースケースdoSomething().then(function(value) { console.log('Got a value' + value);});

function doSomething() { return { then: function (callback) { var value = 42; callback(value); } };}

Page 21: JavaScript非同期処理 入門

2-1. シンプルなユースケースdoSomething().then(function(value) { console.log('Got a value' + value);});

function doSomething() { return { then: function (callback) { var value = 42; callback(value); } };}

Page 22: JavaScript非同期処理 入門

2-1. シンプルなユースケースdoSomething().then(function(value) { console.log('Got a value' + value);});

function doSomething() { return { then: function (callback) { var value = 42; callback(value); } };}

Page 23: JavaScript非同期処理 入門

2-1-1. プロミス型を定義するオレオレクラス構文を勝手に導入して書き直すと…

class Promise { var callback = null; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

← Callback を格納するプロパティ← Callback を予約するメソッド

← 予約された Callback を実行する メソッド ( リゾルバ )

← コンストラクタ。 外部から渡されてきた クロージャにリゾルバを 渡している。 

Page 24: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = null; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

こう動いて欲しい(動くとは言ってない)

Page 25: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = null; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

忘れられたコンストラクタくん

Page 26: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = …; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

Page 27: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = …; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

遅れてきたコンストラクタくん

Page 28: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = …; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

Page 29: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = …; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

クラスメソッドへのポインタ的なイメージ

Page 30: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = …; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

Page 31: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = …; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

Page 32: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = …; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

Page 33: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = null; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

実際はこうなってしまう!

Page 34: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = null; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

Page 35: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = null; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

Page 36: JavaScript非同期処理 入門

2-1-1. プロミス型を定義する

class Promise { var callback = null; function then(cb) { callback = cb; } function resolve(value) { callback(value); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

doSomething().then(function(value) { console.log('Got a value:' + value);});

Page 37: JavaScript非同期処理 入門

3. Promise は状態を持っている

Pending(待機中 )Fulfilled

Resolved(成功した)

Rejected(失敗した )

•Promise の 3状態

今回は省略

Page 38: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'pending'; var value; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

Page 39: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'pending'; var value; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

Page 40: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'pending'; var value; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

今回は同期的な処理

Page 41: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'pending'; var value; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

Page 42: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

Page 43: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

Page 44: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

Page 45: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

Page 46: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

Page 47: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

Page 48: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

Page 49: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

Page 50: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { var value = 42; resolve(value); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});promise.then(function(value) { console.log('Got a value:' + value);});

Page 51: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'pending'; var value; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

もし非同期な処理だったら…

Page 52: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'pending'; var value; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

32時間後に予約

Page 53: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'pending'; var value; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

Page 54: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'pending'; var value; var deferred; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

Page 55: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'pending'; var value; var deferred = …; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

Page 56: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'pending'; var value; var deferred = …; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

Page 57: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'pending'; var value; var deferred = …; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

32時間後なう

Page 58: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'pending'; var value; var deferred = …; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

Page 59: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred = …; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

Page 60: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred = …; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

Page 61: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred = …; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

Page 62: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred = …; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

Page 63: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred = …; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

Page 64: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred = …; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

Page 65: JavaScript非同期処理 入門

3. Promise は状態を持っている

class Promise { var state = 'resolved'; var value = 42; var deferred = …; function resolve(newValue) { value = newValue; state = 'resolved'; if (deferred) { handle(deferred); } } function handle(onResolved) { if (state === 'pending') { deferred = onResolved; return; } onResolved(value); } function then(onResolved) { handle(onResolved); } function Promise(fn) { fn(resolve); }}

function doSomething() { return new Promise(function(resolve) { setTimeout(function () { var value = 42; resolve(value); }, 114514); });}

var promise = doSomething();promise.then(function(value) { console.log('Got a value:' + value);});sleep(114514);promise.then(function(value) { console.log('Got a value:' + value);});

Page 66: JavaScript非同期処理 入門

成し遂げたぜ

Page 67: JavaScript非同期処理 入門

くぅ〜疲れましたwこれにて完結です(完結してない)ホントだったらこの辺までやりたかった

• Promise のチェイン• Promise のリジェクト• Promise における例外処理

⇛ せっかくなので次章で使い方だけ紹介します!

Page 68: JavaScript非同期処理 入門

4-1. ECMAScript 6 編

4. Promise の使い方を覚える

Page 69: JavaScript非同期処理 入門

ECMAScript 6• ECMAScript ってそもそも何?• JavaScript の標準規格• ネットワークで例えると• TCP/IP JavaScript⇛• OSI参照モデル ⇛ ECMAScript

• 現在最も普及しているのは ECMAScript 5 互換の実装 ( 多分 )

• ECMAScript 6 の新機能 (ごく一部 )• Arrow Function … function (a) { return b; } を

(a) => { return b; } または (a) => b と書ける this がより直感的に使えるメリットもある

• Class … 「オレオレクラス構文」みたいなのがマジで書ける            但しメンバ変数は含められない…

• Promise … 今回途中まで実装したようなやつ• Generator …  途中で中断してまだ再開したり出来る関数

Promise と組み合わせると最強

Page 70: JavaScript非同期処理 入門

then のチェインArrowFunction を使いながら復習

 

var foo = (i) => { return new Promise((resolve, reject) => { setTimeout(() => { console.log('OK: ' + i); resolve(i + 1); }, 1000); });};

foo(1).then(foo).then(foo).then(foo);

Page 71: JavaScript非同期処理 入門

then のチェインthen から呼ばれるコールバックの中でPromise を return

⇛ then がチェイン出来る!

var foo = (i) => { return new Promise((resolve, reject) => { setTimeout(() => { console.log('OK: ' + i); resolve(i + 1); }, 1000); });};

foo(1).then(foo).then(foo).then(foo);

OK: 1OK: 2OK: 3OK: 4

Page 72: JavaScript非同期処理 入門

失敗時には reject を利用 then の第 2引数コールバックは reject 時に発火⇛ 以降の resolve は行われない

var foo = (i) => { return new Promise((resolve, reject) => { setTimeout(() => { if (i < 3) { console.log('OK: ' + i); resolve(i + 1); } else { reject('ファッ!? '); } }, 1000); });};

var bar = (msg) => { console.error(msg);};

foo(1).then(foo, bar).then(foo, bar).then(foo, bar);

OK: 1OK: 2ファッ!?

Page 73: JavaScript非同期処理 入門

reject は末尾だけで十分末尾で必ず拾ってくれます

var foo = (i) => { return new Promise((resolve, reject) => { setTimeout(() => { if (i < 3) { console.log('OK: ' + i); resolve(i + 1); } else { reject('ファッ!? '); } }, 1000); });};

var bar = (msg) => { console.error(msg);};

foo(1).then(foo).then(foo).then(foo).then(null, bar);

Page 74: JavaScript非同期処理 入門

reject のみの then は catch にこんな書き方もできます

var foo = (i) => { return new Promise((resolve, reject) => { setTimeout(() => { if (i < 3) { console.log('OK: ' + i); resolve(i + 1); } else { reject('ファッ!? '); } }, 1000); });};

var bar = (msg) => { console.error(msg);};

foo(1).then(foo).then(foo).then(foo).catch(bar);

Page 75: JavaScript非同期処理 入門

実は throw も捕まえられる?※ 但し非同期処理では不可能

var foo = (i) => { return new Promise((resolve, reject) => { if (Math.random() < 0.5) { console.log('OK'); resolve(); } else { throw new Error('ファッ!? '); } });};

var bar = (e) => { console.error(e.message);};

foo(1).catch(bar);

Page 76: JavaScript非同期処理 入門

即時に resolve / reject するこんな関数作ったったw

var quickResolve = (value) => { new Promise((resolve, reject) => resolve(value));};var quickReject = (msg) => { new Promise((resolve, reject) => reject(msg));};

Page 77: JavaScript非同期処理 入門

即時に resolve / reject するそれ、最初からあるんです。

Promise.resolve = (value) => { new Promise((resolve, reject) => resolve(value));};Promise.reject = (msg) => { new Promise((resolve, reject) => reject(msg));};

Page 78: JavaScript非同期処理 入門

即時に resolve / reject する無理矢理つかってみよう

var a = (i) => Promise.resolve(i + 1);var b = (i) => Promise.resolve(i + 1);var c = (i) => Promise.resolve(i + 1);var d = (i) => console.log(i);

a(10).then(b).then(c).then(d);

13

Page 79: JavaScript非同期処理 入門

途中からは return = resolve実はこう書いても自動的に Promise.resolve してくれる

var a = (i) => Promise.resolve(i + 1);var b = (i) => i + 1;var c = (i) => i + 1;var d = (i) => console.log(i);

a(10).then(b).then(c).then(d);

Page 80: JavaScript非同期処理 入門

Promise で並列処理 (all)• 同時にスタートして全部の成功を期待する

var waitSec = (i) => { console.log('I wait for ' + i + ' sec'); return new Promise((resolve, reject) => { setTimeout(() => resolve(i), i * 1000); });};

var promises = [waitSec(1), waitSec(2), waitSec(3)];Promise.all(promises) .then(results => console.log(results));

I wait for 1 secI wait for 2 secI wait for 3 sec [1, 2, 3]

Page 81: JavaScript非同期処理 入門

Promise で並列処理 (race)• 同時にスタートして一番早い成功または失敗を受け付ける

一番早い「成功のみ」ってどうやって書くの?⇛ 「⇛ Promise.any 」でググるとライブラリとかあるよ

var waitSec = (i) => { console.log('I wait for ' + i + ' sec'); return new Promise((resolve, reject) => { setTimeout(() => resolve(i), i * 1000); });};

var promises = [waitSec(1), waitSec(2), waitSec(3)];Promise.race(promises) .then(result => console.log(result));

I wait for 1 secI wait for 2 secI wait for 3 sec1

Page 82: JavaScript非同期処理 入門

4-2. jQuery編

4. Promise の使い方を覚える

Page 83: JavaScript非同期処理 入門

jQuery にも Promise はある!• その前に ECMAScript6 の Promise の別の書き方を紹介

• jQuery

return new Promise((resolve, reject) => { if (…) { resolve(…); } else { reject(…); }});

var deferred = Promise.defer();if (…) { deferred.resolve(…);} else { deferred.reject(…);}return deferred.promise;

・ネストが減る!・でも非標準 / 非推奨

var deferred = $.Deferred();if (…) { deferred.resolve(…);} else { deferred.reject(…);}return deferred.promise();

Page 84: JavaScript非同期処理 入門

jQuery.ajax の返り値• jqXHR• Promise そのものじゃないんだけど

Promise の動きをすることが出来るXMLHttpRequest 関連の何か

$.ajax({ type: 'GET', url: A}).then(function () { return $.ajax({ type: 'GET', url: B, });}).then(function () { console.log('OK!');});

Page 85: JavaScript非同期処理 入門

5. おまけ5-1. ECMAScript 6 と ECMAScript 7 のこれから

Page 86: JavaScript非同期処理 入門

非同期処理って分かりにくい• 初心者だけど失礼するゾ〜 ( 無知 ) 非同期処理分かりに

く過ギィ!自分、同期処理で書いていいっすか?めんどくさいからやりたい放題書いてやるぜー頭悪そうなコード書いてすみません!約束しますから! (Promise するとは言ってない )

Generator の出番

Page 87: JavaScript非同期処理 入門

Generator とは• 途中で値を返しながら処理を中断出来るクロージャ• function *() { … } のようにアスタリスクをつけて定義• yield キーワードで値を返す

• スライド紹介で割愛• 引用スライド中の言語は PHP• PHP は比較的知らない人でも読みやすい(はず)

PHP における I/O 多重化と yieldhttp://www.slideshare.net/techblogyahoo/phpioyield-phpcon2014

Page 88: JavaScript非同期処理 入門

Generator を活用var foo = (i) => { return Promise.resolve(i).then((i) => { return i + 1; }).then((i) => { return i + 1; }).then((i) => { return i + 1; }).then((i) => { return i + 1; })};foo(1).then((i) => console.log(i));

var co = require('co');

var gen = function *(i) { i = yield i + 1; i = yield i + 1; i = yield i + 1; yield i + 1;};

co(gen(1)).then(i => console.log(i));

Page 89: JavaScript非同期処理 入門

ECMAScript 7 だと…

var co = require('co');

var gen = function *(i) { i = yield i + 1; i = yield i + 1; i = yield i + 1; yield i + 1;};

co(gen(1)).then(i => console.log(i));

• async / await という C# のような構文が使える• その代わりクロージャは使えない

async function foo(i) { i = await i + 1; i = await i + 1; i = await i + 1; return await i + 1;};

foo(1).then(i => console.log(i));

Page 90: JavaScript非同期処理 入門

まとめ• 馬鹿正直に書いてるとコールバックネスト地獄に陥る

• Promise を使うと多少読みにくいけど回避出来る• jQuery では $.Deferred で以前から使えた• ECMAScript 6 から new Promise(…) で使える

• Generator を使うと読みやすいまま回避出来る• ECMAScript 6 から function *() { … } で使える• co ライブラリに頼る必要がある

• async / await を使うと更にシンプルに回避できる• ライブラリ要らず!• 但し ECMAScript 7 からしか使えない

Page 91: JavaScript非同期処理 入門

     チカレタ…