secondstreet / talker.js

A tiny, promise-based library for cross-origin communication between frames and windows.
http://drive.secondstreet.com/introducing-talker/
MIT License
33 stars 10 forks source link

Provide destroy/teardown method #1

Open janstadt opened 9 years ago

janstadt commented 9 years ago

We're using talker.js in an angular SPA that loads an iframe after clicking on an item from a list. Upon click, we launch an iframe containing an application that is required to setup a talker instance to communicate with the parent. The parent app controls when the iframe is present, but when we navigate away from the iframe, the window and event listeners are still present via window["frameName"]. If we navigate away from the iframe while waiting for a message to be responded to, the Talker instance gets nulled out BUT the event listener is still alive so the _receiveMessage method still gets called and throws an exception.

Talker.prototype.destroy = function () {
    if (this.rejectTimeout) {//see below on this
        clearTimeout(this.rejectTimeout);
    }
    if (this._listener) {
        window.removeEventListener("message", this._listener, false);
        this._listener = null;
    }
};

We also have a number of scenarios that are fire and forget type of messages where the outer iframe just tells the inner one something and does not require a response. It would be nice to have a send and sendAsyc method where the sendAsync method creates the promise and requires a response and send just sends the message without creating the promise. The issue happens when we send a message without expecting a response so the promise in the setTimeout gets rejected after the timeout expires. Apart from setting our timeout to something astronomical, we end up with a lot of rejected promises with the timeout message. Would you consider doing something like this:

Talker.prototype.sendAsync = function(namespace, data, responseToId) {
    var message = new Talker.OutgoingMessage(this, namespace, data, responseToId);

    var promise = pinkySwearPromise();
    this._sent[message.id] = promise;

    this._queue.push(message);
    this._flushQueue();

    this.rejectTimeout = setTimeout(function() {
        promise(false, [new Error(TALKER_ERR_TIMEOUT)]); // Reject the promise
    }, this.timeout);

    return promise;
    };

Talker.prototype.send = function(namespace, data, responseToId) {
    var message = new Talker.OutgoingMessage(this, namespace, data, responseToId);
this._postMessage(message);
    };

and then in the destroy method we would clear the this.rejectTimeout timer. At the moment we are doing these things in our version of talker.js but it might be handy for others who could potentially run into this issue.

Thanks,

Jake

Jayiitb commented 6 years ago

@janstadt Thanks for the thought. I am also facing timeout issue. When do you call destroy? What if someone calls SendAsync multiple times? Then, I guess we'll not be able to destroy individual calls, as you are not keeping rejectTimeout for each calls.. it will be overridden by the next one...if otherwise the promise is not resolved or rejected.