On Thu, Nov 6, 2008 at 12:27 AM, Giulio Cesare Solaroli
<[EMAIL PROTECTED]> wrote:
> It has happened to me to require registering an observer before the
> actual source of the signal was created. In these cases, I would just
> register the observer to listen to a given signal on any source. Later
> the relevant object would signal the right message and the observer
> would be triggered.

Ok, but then you also have to filter away the same signal when
originated in other objects, right?

> Or, I need to update an object, whatever it happens to it. So I can
> register for any signal on that given object and trigger an action.

This is kind of interesting. When using MochiKit.Signal, you would
depend on the user calling signal() for each change performed, which
might be unpractical in some cases. Also, when scaling this up for
many objects, you'll run into linear performace degradation due to the
looping through of the MochiKit.Signal._observers array.

An alternative implementation to signals (compared to MochiKit), would
be based on the signal-slot concept from Qt (and elsewhere). In that
model all non-DOM signals are functions, as are all slots. And the
connect() function simply attaches some pre-call and post-call logic
to each signal function, making sure that the connected slot functions
are called.

Using that model, source objects are modified. But since there are no
lists, there is no performance penalty to using many non-DOM signals.
Also, the need for the signal() function would be none, since the
following would do the job:

// setting up objects
var src = { srcMethod: function() { alert("source"); } };
var dst = { dstMethod: function() { alert("dest"); } };
// connecting a signal with the signal-slot mechanism
Signal.connect(src, "srcMethod", dst, "dstMethod");
// calling both the signal function and the slot function
src.srcMethod();

Using this model, it would be trivial to create proxy-objects. I.e.
objects that are copies of a source object, but also calls some
handler code before and after each function call. Don't know if that
would be so very useful, though. But a nice hack. :-)

If anyone is interested, here is some old code I had in my own signal
module before migrating to MochiKit.Signal (stripped for comments &
logging to save space):

Signal = {};

Signal.connect = function(src, signal, destOrFunc, funcOrStr) {
    if (typeof(signal) != "string") {
        throw new TypeError("signal name must be a string");
    }
    var slot = Signal._createSlot(destOrFunc, funcOrStr);
    this._connectDispatcher(src, signal);
    src[signal].postFuncs.push(slot);
}

Signal.connectBefore = function(src, signal, destOrFunc, funcOrStr) {
    if (typeof(signal) != "string") {
        throw new TypeError("signal name must be a string");
    }
    var slot = Signal._createSlot(destOrFunc, funcOrStr);
    this._connectDispatcher(src, signal);
    src[signal].preFuncs.push(slot);
}

Signal.disconnectAll = function(src, signal) {
    if (src == null) {
        throw new TypeError("signal object cannot be null");
    }
    if (signal != null) {
        if (typeof(signal) != "string") {
            throw new TypeError("signal name must be a string");
        }
        this._disconnectDispatcher(src, signal);
    } else {
        for (var n in src) {
            if (typeof(src[n]) == "function") {
                this._disconnectDispatcher(src, n);
            }
        }
    }
}

Signal._createSlot = function(destOrFunc, funcOrStr) {
    if (typeof(funcOrStr) == "string") {
        if (typeof(destOrFunc[funcOrStr]) != "function") {
            throw new TypeError("signal slot '" + funcOrStr + "' is
not a function");
        }
        return MochiKit.Base.bindLate(funcOrStr, destOrFunc);
    } else if (typeof(funcOrStr) == "function") {
        return MochiKit.Base.bindLate(funcOrStr, destOrFunc);
    } else if (typeof(destOrFunc) == "function") {
        return destOrFunc;
    } else {
        throw new TypeError("signal slot is not a function");
    }
}

Signal._connectDispatcher = function(src, signal) {
    if (src == null) {
        throw new TypeError("signal object cannot be null");
    } else if (!(signal in src)) {
        throw new TypeError("signal '" + signal + "' doesn't exist in object");
    }
    var value = src[signal];
    if (value != null && typeof(value.signalFunc) == "function") {
        return;
    }
    src[signal] = function() {
        var self = arguments.callee;
        var res;
        Signal._callSlots(self.dispatchName, self.preFuncs, this, arguments);
        if (typeof(self.signalFunc) == "function") {
            res = self.signalFunc.apply(this, arguments);
        }
        Signal._callSlots(self.dispatchName, self.postFuncs, this, arguments);
        return res;
    }
    src[signal].signalFunc = value;
    src[signal].preFuncs = [];
    src[signal].postFuncs = [];
}

Signal._disconnectDispatcher = function(src, signal) {
    if (src == null) {
        throw new TypeError("signal object cannot be null");
    } else if (!(signal in src)) {
        throw new TypeError("signal '" + signal + "' doesn't exist in object");
    }
    var value = src[signal];
    if (value == null || typeof(value.signalFunc) != "function") {
        return;
    }
    src[signal] = value.signalFunc;
    value.signalFunc = null;
    value.preFuncs = null;
    value.postFuncs = null;
}

Signal._callSlots = function(signalName, slots, obj, args) {
    for (var i = 0; i < slots.length; i++) {
        try {
            slots[i].apply(obj, args);
        } catch (e) {
            MochiKit.Logging.logError("Uncaught exception in call from
" + signalName, e);
        }
    }
}

> How do you see integration between signals and deferred?
>
> I am very interested in this, as our application make extensive use of
> both, and we are now thinking about removing our custom notification
> center in order to simplify all signaling code and settle for a single
> API, and we are going to consolidate on MochiKit.Signal.

Basically I'm thinking along the lines of MochiKit.AJAX. But I'd like
to be able to keep different AJAX calls separated. So perhaps like
this (with improved naming of course):

// create a generic HTTP/Ajax dispatcher object
var dispatcher = new HttpDispatcher({ url: "http://localhost/json/";,
method: "POST", response: "JSON" });

// create some functions that performs AJAX calls
dispatcher.createFunction("getUsers", { method: "GET" });
dispatcher.createFunction("updateUser", { args: ["name", "email"] });

// call the functions and get a deferred objects back
dispatcher.getUsers();
dispatcher.updateUser('john', '[EMAIL PROTECTED]');

// connect signals to specific methods (signals on AJAX response)
connect(dispatcher, "getUsers", doSomething);

// connect signals to generic AJAX events on the dispatcher
connect(dispatcher, "onresponse", doSomethingElse);
connect(dispatcher, "onerror", alert);

Anyway, the above is just an idea that I'm playing around with.
Haven't thought so much about this, actually... :-)

Cheers,

/Per

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"MochiKit" group.
To post to this group, send email to mochikit@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to