;(function ($) { "use strict"; /** * 時間管理時のDeferred実装用Deferredオブジェクト * @typedef jQueryTimeDeferred * @type {jQuery.Deferred} * @property {Function} clear タイマーをキャンセルさせる為のメソッド */ /** * setInterval の Deferred 実装 * $.interval(time) の様に呼び出す。 * 戻り値は Promise で、 関数として .clear() が追加されている。 * .done - 未使用 * .fail - 関数 .clear() を実行することにより呼ばれる * .progress - timeミリ秒ごとに呼ばれる * $.interval(time) では コールバックのthis に null が入るのに対して * $(sel).interval(time) では コールバックの this に 選択設定した要素が入る。(画面上に存在しているかは非保証) * @param {!Number} [time] time秒毎に繰り返す時間 (ms) * @return {jQueryTimeDeferred} */ var interval = function (time) { if (typeof time !== "number") { time = interval.options.defaultInterval; } var self = this, d = $.Deferred(), key = setInterval(function () { d.notifyWith(self); }, time), p = d.promise(); p.clear = function () { clearInterval(key); d.rejectWith(self); }; return p; }; interval.options = { defaultInterval : 100 }; /** * setTimeout の Deferred 実装 * $.timeout(time) の様に呼び出す。 * 戻り値は Promise で、 関数として .clear() が追加されている。 * .done - timeミリ秒経過して余裕があれば呼ばれる(余裕が無ければ余裕があるタイミングで呼ばれる) * .fail - 関数 .clear() を実行することにより呼ばれる * .progress - 未使用 * $.timeout(time) では コールバックのthis に null が入るのに対して * $(sel).timeout(time) では コールバックの this に 選択設定した要素が入る。(画面上に存在しているかは非保証) * @param {Number} [time] time秒後に呼び出す予定の時間 (ms) * @return {jQueryTimeDeferred} */ var timeout = function (time) { if (typeof time !== "number") { time = timeout.options.defaultTime; } var self = this, d = $.Deferred(), key = setTimeout(function () { d.resolveWith(self); }, time), p = d.promise(); p.clear = function () { clearTimeout(key); d.rejectWith(self); }; return p; }; timeout.options = { defaultTime : 1 }; /** * @param {Number} [time] * @return {jQueryTimeDeferred} */ $.interval = function (time) { return interval.call(null, time); }; /** * @param {Number} [time] * @return {jQueryTimeDeferred} */ $.fn.interval = function (time) { return interval.call(this, time); }; /** * @param {Number} [time] * @return {jQueryTimeDeferred} */ $.timeout = function (time) { return timeout.call(null, time); }; /** * @param {Number} [time] * @return {jQueryTimeDeferred} */ $.fn.timeout = function (time) { return timeout.call(this, time); } })(jQuery); //テスト ;(function($){ $(function(){ var $result = $("#result"), dTimeoutClear = null, dIntervalClear = null, intervalCount = 0, set_log = function(text){ $result.prepend($("<li/>").text(text)); }, set_star = function(className){ $(this).closest("li").append( $("<span/>").addClass(className).text("*") ); }; $("#call-timeout").on("click",function(e){ //5000ms で timeout する if(dTimeoutClear){ dTimeoutClear(); } dTimeoutClear = $(this).timeout(5000) .always(function(){ dTimeoutClear = null; }) .done(function(){ set_log("timeout Finish!"); set_star.call(this,"finish"); }) .fail(function(){ set_log("timeout Cancel"); set_star.call(this,"clear"); }).clear; }); $("#timeout-cancel").on("click",function(){ //timeout のキャンセル if(dTimeoutClear){ dTimeoutClear(); set_star.call(this,"clear"); }else{ set_log("not start timeout."); } }); $("#call-interval").on("click",function(){ //3000ms で interval する if(dIntervalClear){ dIntervalClear(); } dIntervalClear = $(this).interval(3000) .progress(function(){ set_log( "intervalCount["+(intervalCount++)+"]"); set_star.call(this,"progress"); }) .always(function(){ dIntervalClear = null; }) .fail(function(){ set_log("interval Cancel"); set_star.call(this,"clear"); }).clear; }); $("#interval-cancel").on("click",function(){ //intervalのキャンセル if(dIntervalClear){ dIntervalClear(); set_star.call(this,"clear"); }else{ set_log("not start interval."); } }); }); })(jQuery);
<h1>jQuery Deferredを用いた setTimeout,setInterval の実装例</h1> <ul> <li><a id="call-timeout">timeoutテスト(5s)</a></li> <li><a id="timeout-cancel">timeout キャンセル</a></li> <li><a id="call-interval">intervalテスト(3s)</a></li> <li><a id="interval-cancel">intervl キャンセル</a></li> </ul> <ul id="result"></ul>
a[id]{ cursor:pointer; color:blue; } a[id]:hover{ font-weight:bold; } .finish{ color:red; } .clear{ color:yellow; } .progress{ color:green; }