I've wrote a very simple implementation of Deferred / Promise pattern (inspired by jQuery's `$.deferred`) for my tiny project (which does not use jQuery)

It can handle multiply `onSuccess` an `onFail` callbacks with result caching. Example in comments above the code.

```
/**
 * defer() returns methods:
 *      resolve(data) - request is successfully resolved (returns nothing)
 *      reject(msg) - request if failed (returns nothing)
 *      promise() - returns promise function
 *
 * promise() returns methods:
 *      done(successfulCallback) - add on successful callback (returns nothing)
 *      fail(failCallback) - add on fail callback (returns nothing)
 *
 * Example:
 *
 * function someHeavyRequest(url) {
 *      var d = defer();
 *      doHeavyRequest(url,
 *          function (data) {
 *              // on success
 *              // ...do something
 *              d.resolve(data);
 *          },
 *          function (data) {
 *              // on fail
 *              // ...do something
 *              d.reject(data);
 *          });
 *      return d.promise();
 * }
 *
 * var req = someHeavyRequest("http://some.url/of/request/");
 *
 * req.done(function (data) {
 *      console.log("We got it!");
 *      console.log(data);
 * });
 *
 * req.done(function (data) {
 *      console.log("We got it again without new request!");
 *      console.log(data);
 * });
 *
 * req.fail(function (data) {
 *      console.error("Something wrong");
 *      console.error(data);
 * });
 *
 */
function defer () {
    var status = 0, // 0 = in progress / 1 = successful / -1 = fail
        callbacks = { done: [], fail: [] },
        args = { resolve: [], reject: [] },
        execute = function (callbacks, args) {
            var f;
            while (callbacks.length) {
                f = callbacks.shift();
                if (f) f.apply(this, args);
            }
        };

    return {
        promise: function () {
            return {
                done: function (callback) {
                    callbacks.done.push(callback);
                    if (status === 1) {
                        execute(callbacks.done, args.resolve);
                    }
                },

                fail: function (callback) {
                    callbacks.fail.push(callback);
                    if (status === -1) {
                        execute(callbacks.fail,args.reject);
                    }
                }
            };
        },

        resolve: function () {
            status = 1;
            args.resolve = arguments;
            execute(callbacks.done, args.resolve);
        },

        reject: function () {
            status = -1;
            args.reject = arguments;
            execute(callbacks.fail, args.reject);
        }
    };
}

```