Edit in JSFiddle

var Deferred = function(context){

    if( ! (this instanceof Deferred) ){
        return new Deferred( context );
    }

    this._resolved = null;
    this._rejected = null;
    this._dones = [];
    this._fails = [];
    this._always = [];
    this._context = context || this;
}

Deferred.prototype = {

    promise: function(){

        var dfd = this;

        var p = {
             done: dfd.done.bind(dfd)
            ,fail: dfd.fail.bind(dfd)
            ,always: dfd.always.bind(dfd)
        }

        return p;
    }

    ,resolve: function(){

        if( this._resolved || this._rejected ){ return this; }

        var i
            ,args = Array.prototype.slice.call(arguments);
        
        this._resolved = args;
        this._notify( this._dones, args );
        this._notify( this._always, args );
        
        return this;
    }
    
    ,reject: function(){

        if( this._resolved || this._rejected ){ return this; }

        var i
            ,args = Array.prototype.slice.call(arguments);
        
        this._rejected = args;
        this._notify( this._fails, args );
        this._notify( this._always, args );

        return this;
    }
    
    ,done: function( cb ){
        this._dones.push( cb );

        if( this._resolved ){
            cb.apply( this._context, this._resolved );
        }

        return this;
    }

    ,fail: function( cb ){
        this._fails.push( cb) ;

        if( this._rejected ){
            cb.apply( this._context, this._rejected );
        }

        return this;
    }

    ,always: function( cb ){
        this._always.push( cb );

        if( this._rejected || this._resolved ){
            cb.apply( this._context, this._rejected || this._resolved );
        }

        return this;
    }

    ,_notify: function( cbs, args ){
        var i;

        for( i = 0; i < cbs.length; i++ ){
            cbs[i].apply(this._context, args);
        }
    }
}

var dfd = new Deferred;
dfd.done(function(arg1){ console.log('done', arg1) });
dfd.fail(function(arg1){ console.log('fail', arg1) });
dfd.always(function(arg1){ console.log('always', arg1) });
dfd.resolve( 'from the resolution' );

dfd.done(function(arg1){ console.log('done afterwards', arg1) });
dfd.reject('from the invalid rejection');
dfd.always(function(arg1){ console.log('always afterwards', arg1) });                         
console.log('break');
                         
dfd = new Deferred;
dfd.done(function(arg1){ console.log('done', arg1) });
dfd.fail(function(arg1){ console.log('fail', arg1) });
dfd.always(function(arg1){ console.log('always', arg1) });
                           
var p = dfd.promise();
p.fail(function(arg1){ console.log('fail via promise'); });
p.always(function(arg1){ console.log('always via promise'); });
                           
dfd.reject( 'from the rejection' );

dfd.fail(function(arg1){ console.log('fail afterwards', arg1) });
dfd.reject( 'from the invalid rejection' );  
dfd.always(function(arg1){ console.log('always afterwards', arg1) });