jQuery Deferredを用いた setTimeout,setInterval の実装例

by juner

HTML

<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>

CSS

a[id]{
    cursor:pointer;
    color:blue;
}
a[id]:hover{
    font-weight:bold;
}
.finish{
    color:red;
}
.clear{
    color:yellow;
}
.progress{
    color:green;
}

JavaScript

;(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 ()...