Upload
satoshi-matsushita
View
593
Download
4
Embed Size (px)
DESCRIPTION
コールバック地獄の話
Citation preview
Hello Callback Hell.2014/10/18 Miyazaki.js
Satoshi Matsushita @satoshi_m8a
自己紹介名前:松下 聡史株式会社 アラタナ
出身:島根県松江市
趣味:読書、プログラミング、サーフィン、ネットサーフィン
主な出現場所:タリーズ宮崎高千穂通店
好きな言語:Scala, JavaScript
個人的な制作物:M+Web FONTS Subsetter : Play EC(EC-CUBEのクローン)
何かのサービスを呼び出して、その結果を使って別のサービスを呼び出す。
レジュメ
• コールバック関数が必要になる場面
• コールバック関数が多くなることの問題点(いわゆるコールバック地獄)
• $.Deferredの紹介
例0
ある数字にランダムな数字を加えて、計算過程を叫ぶ関数
! var getRandomInt = function (min, max) { return Math.floor(Math.random() * (max - min)) + min; }; ! var sayCalcProcess = function (a, b, result) { console.log('WRRRRYYYY ' + a + ' + ' + b + ' = ' + result); }; ! var sayRandomCalc = function (base) { var random = getRandomInt(0, 10); var result = base + random; sayCalcProcess(base, random, result); return result; }; ! sayRandomCalc(10);
例1
指定秒数遅れて、ある数字にランダムな数字を加えて、計算過程を叫び、結果を表示する関数
var sayRandomCalcDelay = function (params) { setTimeout(function () { var result = sayRandomCalc(params.base); params.success(result); }, params.delaySeconds * 1000); }; ! sayRandomCalcDelay({ base: 0, delaySeconds: 1, success: function (result) { console.log('final result is ' + result); } });
• 何かのWebサービスを想定してもよい。
• $.ajax() $.get() $.post とかで呼び出す。
• 結果は遅れて返ってくる。
• 結果が返った時に実行する関数→コールバック関数
例2
指定秒数遅れて、ある数字にランダムな数字を加えて、その結果に指定秒数遅れてランダムな数字を加えて、計算過程を叫び、結果を表示する関数
sayRandomCalcDelay({ base: 0, delaySeconds: 1, success: function (result) { sayRandomCalcDelay({ base: result, delaySeconds: 2, success: function (result) { console.log('final result is ' + result); } }); } });
例3
関数化しよう function delay1(base) { sayRandomCalcDelay({ base: base, delaySeconds: 1, success: delay2 }); } ! function delay2(base) { sayRandomCalcDelay({ base: base, delaySeconds: 2, success: showResult }); } ! function showResult(result) { console.info('final result is ' + result); } !! delay1(0);
例4
まだ大丈夫。
function delay1(base) { sayRandomCalcDelay({ base: base, delaySeconds: 1, success: delay2 }); } ! function delay2(base) { sayRandomCalcDelay({ base: base, delaySeconds: 2, success: delay3 }); } ! function delay3(result) { sayRandomCalcDelay({ base: result, delaySeconds: 3, success: showResult }); } ! function showResult(result) { console.info('final result is ' + result); } !! delay1(0);
ここで仕様変更
計算結果が偶数ならsuccessコールバックを呼び、奇数ならerrorコールバックを呼ぶ
var sayRandomCalcDelay = function (params) { setTimeout(function () { var result = sayRandomCalc(params.base); if (result % 2 === 0) { params.success(result); } else { params.error(result); } }, params.delaySeconds * 1000); };
例5
お、おう
function delay1(base) { sayRandomCalcDelay({ base: base, delaySeconds: 1, success: delay2, error: onError }); } ! function delay2(base) { sayRandomCalcDelay({ base: base, delaySeconds: 2, success: delay3, error: onError }); } ! function delay3(base) { sayRandomCalcDelay({ base: base, delaySeconds: 3, success: showResult, error: onError }); }
function showResult(result) { console.info('final result is ' + result); } ! function onError(result) { console.error('error! ' + result + ' is odd number'); } ! delay1(0);
また、仕様変更
• delay1→delay2→delay3 の順番でしたが、
• delay3→delay2→delay1 の順番でも呼び出せるように。
ぐはっ
function delay1(base) { sayRandomCalcDelay({ base: base, delaySeconds: 1, success: delay2, error: onError }); } ! function delay2(base) { sayRandomCalcDelay({ base: base, delaySeconds: 2, success: delay3, error: onError }); } ! function delay3(base) { sayRandomCalcDelay({ base: base, delaySeconds: 3, success: showResult, error: onError }); }
function showResult(result) { console.info('final result is ' + result); } ! function onError(result) { console.error('error! ' + result + ' is odd number'); } ! delay1(0);
やりたいこと
• ある関数を呼び出し、計算が成功したら次の関数を呼び出し、最後まで成功したら、結果を表示する。
• 途中で計算が失敗したら、途中の計算を止めてエラーメッセージを表示する。
• 呼び出しの順番が入れ替わっても対応できる。
jQuery.Deferred() を使って簡潔に表現する。
delay1(0) .then(delay2) .then(delay3) .then(showResult) .fail(onError);
非同期関数をDeferredに対応させる
var sayRandomCalcAsync = function (params) { var d = new $.Deferred(); ! sayRandomCalcDelay({ base: params.base, success: function (result) { if (typeof params.success === 'function') { params.success(result); } d.resolve(result); }, error: function (result) { if (typeof params.error === 'function') { params.error(result); } d.reject(result); }, delaySeconds: params.delaySeconds }); ! return d.promise(); };
Deferredオブジェクトを生成
Promiseオブジェクトを返す
計算が成功したら、resolve関数に計算結果を引数にして呼び出す
計算が失敗したら、reject関数を呼び出す
jQuery.Deferredに対応した関数は組み合わせ自由
delay3(0) .then(delay3) .then(delay1) .then(showResult) .fail(onError);
jQuery 1.5~• jQuery 1.5 から$.ajax, $.get, $.post はDeferredに対応
$.ajax({ type: "POST", url: url, data: data, success: success, dataType: dataType });
return $.ajax({ type: "POST", url: url, data: data, dataType: dataType });
jQuery.when()を使って複数のDeferredを組み合わせる
$.when(delay1(0), delay2(0)).done(function (a, b) { showResult(a + b); });
参考
• 爆速でわかるjQuery.Deferred超入門 http://techblog.yahoo.co.jp/programming/jquery-deferred/
• Deferred Object | jQuery API Documentationhttp://api.jquery.com/category/deferred-object/
こんなこともできます
delay1
delay3delay2
delay2 delay2
when
何かに見えてきませんか?
そうです、関数合成!!
Michael Fogus 著、和田 祐一郎 訳
• 関数型言語ではない、JavaScriptで関数型プログラミングをする方法
• $.Deferredの紹介も少しある。
• 関数(パーツ)を組み合わせて、複雑な処理を簡単に記述できる。
• バグが発生しにくい。
• 発生しても直ぐに原因を特定できる。
• 変更に強い。
すごいHaskellたのしく学ぼう!
やってます!
Play Framework2(Scala)
Webアプリケーションも関数型で作る
すみませんでした!!