How can server interrupt client in browser?

Discussion in 'Javascript' started by Anil, Oct 21, 2008.

  1. Anil

    Anil Guest

    I have a Javascript program which runs in the browser and has
    functions work(), and stop().
    It listens to commands from the server to work() and can be
    interrupted by the server to stop().
    I am using XmlHttpRequest to talk to the server.
    So I use http GET to send a command "ready" to the server, which
    replies at some point in time by sending "work" which is invoked by
    the callback.

    As per my understanding, the browser client is single threaded. How to
    get the server to interrupt the browser client to say "stop"?

    I modified Flanagan's example code here:

    var HTTP = {

    // This is a list of XMLHttpRequest creation factory functions to try
    _factories : [
    function() { return new XMLHttpRequest(); },
    function() { return new ActiveXObject("Msxml2.XMLHTTP"); },
    function() { return new ActiveXObject("Microsoft.XMLHTTP"); }
    ],

    // When we find a factory that works, store it here
    _factory : null,

    // Create and return a new XMLHttpRequest object.
    //
    // The first time we're called, try the list of factory functions
    until
    // we find one that returns a nonnull value and does not throw an
    // exception. Once we find a working factory, remember it for later
    use.
    //
    newRequest : function() {
    if (HTTP._factory != null) return HTTP._factory();

    for(var i = 0; i < HTTP._factories.length; i++) {
    try {
    var factory = HTTP._factories;
    var request = factory();
    if (request != null) {
    HTTP._factory = factory;
    return request;
    }
    }
    catch(e) {
    continue;
    }
    }

    // If we get here, none of the factory candidates succeeded,
    // so throw an exception now and for all future calls.
    HTTP._factory = function() {
    throw new Error("XMLHttpRequest not supported");
    }
    HTTP._factory(); // Throw an error
    },

    /**
    * Use XMLHttpRequest to fetch the contents of the specified URL
    using
    * an HTTP GET request. When the response arrives, pass it (as plain
    * text) to the specified callback function.
    *
    * This function does not block and has no return value.
    */
    toServer : function(url) {
    var request = HTTP.newRequest();
    request.onreadystatechange = function() {
    if (request.readyState == 4 && request.status == 200)
    MyProxy.fromServer(request.responseText);
    }
    request.open("GET", url, true); // 3rd param implies asynchronous
    console.log("sending " + url);
    request.send(null);
    },

    };

    ......
    // MyProxy
    ....
    fromServer: function(command) {
    console.log("fromServer: " + command);
    eval(command);
    },
    thanks,
    Anil
    Anil, Oct 21, 2008
    #1
    1. Advertising

  2. Anil

    sasuke Guest

    On Oct 22, 12:49 am, Anil <> wrote:
    > As per my understanding, the browser client is single threaded. How to
    > get the server to interrupt the browser client to say "stop"?


    The communication has to be initiated by the client. Either keep
    polling the server periodically[Ajax with polling] or use something
    along the lines of Comet technology [Web Server push enabled by the
    use of long held http connections].
    <URL: http://en.wikipedia.org/wiki/Comet_(programming)>

    /sasuke
    sasuke, Oct 22, 2008
    #2
    1. Advertising

  3. Anil

    Anil Guest

    On Oct 21, 10:46 pm, sasuke <> wrote:
    > On Oct 22, 12:49 am, Anil <> wrote:
    >
    > > As per my understanding, the browser client is single threaded. How to
    > > get the server to interrupt the browser client to say "stop"?

    >
    > The communication has to be initiated by the client. Either keep
    > polling the server periodically[Ajax with polling] or use something
    > along the lines of Comet technology [Web Server push enabled by the
    > use of long held http connections].
    > <URL:http://en.wikipedia.org/wiki/Comet_(programming)>
    >
    > /sasuke


    Thanks for replying. I was wondering if a trick like this would work,
    but it doesn't seem to. Is it a bug in my implementation or is it
    conceptually faulty?
    In MyProxy.fromServer(), issue another toServer("url").
    Thus there will always be a GET request pending. Since it is
    asynchronous, it will return immediately. But the callback will occur
    while the client is executing.
    so what happens here - what will the browser do - will it simply
    block, or a new thread be created? My understanding is stuck here.
    Anil, Oct 22, 2008
    #3
  4. Anil

    sasuke Guest

    On Oct 22, 7:20 pm, Anil <> wrote:
    > On Oct 21, 10:46 pm, sasuke <> wrote:
    >
    > > On Oct 22, 12:49 am, Anil <> wrote:

    >
    > > > As per my understanding, the browser client is single threaded. How to
    > > > get the server to interrupt the browser client to say "stop"?

    >
    > > The communication has to be initiated by the client. Either keep
    > > polling the server periodically[Ajax with polling] or use something
    > > along the lines of Comet technology [Web Server push enabled by the
    > > use of long held http connections].
    > > <URL:http://en.wikipedia.org/wiki/Comet_(programming)>

    >
    > > /sasuke

    >
    > Thanks for replying. I was wondering if a trick like this would work,
    > but it doesn't seem to. Is it a bug in my implementation or is it
    > conceptually faulty?
    > In MyProxy.fromServer(), issue another toServer("url").
    > Thus there will always be a GET request pending. Since it is
    > asynchronous, it will return immediately. But the callback will occur
    > while the client is executing.
    > so what happens here - what will the browser do - will it simply
    > block, or a new thread be created? My understanding is stuck here.


    Javascript implementations don't support threading. When making asyn
    requests, the browser never blocks; instead as soon as a response is
    returned from the server, the callback function is executed which
    performs the required processing.

    Like I mentioned before, just keep polling the server for commands
    using setInterval and make provision for a NO-OP command. Thoroughly
    read the Comet article in case you want to avoid polling. Modern web
    servers like Tomcat come with in-built Comet support.

    /sasuke
    sasuke, Oct 22, 2008
    #4
  5. Anil wrote:
    > I have a Javascript program which runs in the browser and has
    > functions work(), and stop().
    > It listens to commands from the server to work() and can be
    > interrupted by the server to stop().
    > I am using XmlHttpRequest to talk to the server.
    > So I use http GET to send a command "ready" to the server, which
    > replies at some point in time by sending "work" which is invoked by
    > the callback.
    >
    > As per my understanding, the browser client is single threaded.


    That is correct, however it is rather irrelevant here because the point
    in using asynchronous request-response handling (as you do) is to work
    around that.

    > How to get the server to interrupt the browser client to say "stop"?


    One possibility is the obvious:

    fromServer: function(command) {
    console.log("fromServer: " + command);

    if (command != "stop")
    {
    eval(command);
    }
    },

    That is not interrupting anything, though, as nothing needs to be
    interrupted in the first place.

    However, the reference implementation and other implementations also support
    a way to cancel the current HTTP request while it is in progress, the
    abort() method:

    <http://msdn.microsoft.com/en-us/library/ms760305(VS.85).aspx>
    <https://developer.mozilla.org/En/XMLHttpRequest>
    <http://www.opera.com/docs/specs/xhr/index.dml>
    <http://developer.kde.org/documentation/library/3.4-api/khtml/html/xmlhttprequest_8cpp-source.html>
    <http://trac.webkit.org/browser/branches/Safari-3-2-branch/WebCore/xml/XMLHttpRequest.cpp#L481>

    > I modified Flanagan's example code here:


    You should not use Flanagan's code, and particularly not this code as it is
    error-prone.


    PointedEars
    --
    Anyone who slaps a 'this page is best viewed with Browser X' label on
    a Web page appears to be yearning for the bad old days, before the Web,
    when you had very little chance of reading a document written on another
    computer, another word processor, or another network. -- Tim Berners-Lee
    Thomas 'PointedEars' Lahn, Oct 22, 2008
    #5
  6. Anil

    Anil Guest

    Can you please tell me why it is error prone? Is there better code
    that will do the same thing... if so, can you please point me to it?

    Also, "stop" is not for canceling the http request. stop() does a
    specific task.
    thanks,
    Anil

    On Oct 22, 3:21 pm, Thomas 'PointedEars' Lahn <>
    wrote:
    >
    > You should not use Flanagan's code, and particularly not this code as it is
    > error-prone.
    >
    > PointedEars
    Anil, Oct 24, 2008
    #6
  7. Anil wrote:
    > Can you please tell me why it is error prone?


    It uses exception handling without fallback to begin with.

    > Is there better code that will do the same thing...


    Yes.

    > if so, can you please point me to it?


    It is located in your /dev/brain.


    Please don't top-post. Reply below parts of trimmed quotes instead.


    PointedEars
    --
    realism: HTML 4.01 Strict
    evangelism: XHTML 1.0 Strict
    madness: XHTML 1.1 as application/xhtml+xml
    -- Bjoern Hoehrmann
    Thomas 'PointedEars' Lahn, Oct 24, 2008
    #7
  8. Hi Anil,

    > As per my understanding, the browser client is single threaded. How to
    > get the server to interrupt the browser client to say "stop"?


    On the off-chance that you're not like every other xenophobic little-HTTPer
    here, and you won't let any personal prejudices stop you from thinking
    outside the Ajax-box for a moment, let me offer you a Java Applet
    alternative. (If/when Flash or Silverlight get around to supporting UDP you
    can probably do it with them as well.)

    If you'd like to see an example of a threaded Java Applet that receives UDP
    messages from an abitrary server(s), then please: -

    1) Click on the following link and read the instructions:
    http://manson.vistech.net/~tier3/tier3pager.html

    2) Telnet to manson.vistech.net. (If you don't already have an account on
    the Deathrow cluster then please use Username: DEMO Password: USER) and
    then:

    $set term/width=132
    $run sys$users:[users.tier3.web]demo_udp_msg

    3) Enter the IP address of your client node. Your "stock-monitor" from step
    1 should now spring into life with random stock-prices generated at 2sec
    intervals. (NATed clients will find this bit problematic :)

    4) Enter any adhoc messages that you wish to appear in the seperate Java
    Frame on the client.

    OPCOM messages to web-subscribers? CHAT conferences? Stock-Watching? Alarm
    Monitoring? - It's all good!

    The rationale here is not to use up a TCP/IP connection and a server
    process/thread for ad-hoc, asynchronous, broadcasts, and most definitely do
    use something other than a connectionless, context-devoid,
    session-hijackable, pile of http-pooh as your middleware backbone.

    Cheers Richard Maher

    PS. The code for Tier3Pager.java aqnd DEMO_UDP_MSG.COB are below, but all
    can be found at SYS$USERS:[USERS.TIER3.WEB]

    PPS. If this is for the Intranet then you might wish to look at Broadcast or
    even Multicast functionality as well, and eliminate the "subscribe" step
    altogether.

    Tier3Pager.java
    ===========

    /**
    * Copyight Tier3 Software. All rights reserved.
    *
    * Author: Richard Maher
    *
    **/

    import java.applet.Applet;
    import java.awt.*;
    import java.net.*;
    import java.io.IOException;
    import netscape.javascript.JSObject;
    import netscape.javascript.JSException;

    public class Tier3Pager extends Applet
    {
    private String hostName;
    private JSObject browser;
    private static MessageThread socketThread;
    private static Tier3Talk chat;

    public class MessageThread extends Thread
    {
    private DatagramSocket socket;
    private DatagramPacket packet;
    private String threadData;

    public MessageThread(String name, String txt) throws Exception
    {
    super(name);

    byte[] buffer;
    threadData = txt;

    String port = getParameter("PORT");
    String maxBuf = getParameter("MAXBUF");
    try
    {
    if (port == null)
    socket = new DatagramSocket();
    else
    socket = new DatagramSocket(Integer.parseInt(port));

    if (maxBuf == null)
    buffer = new byte[512];
    else
    buffer = new byte[Integer.parseInt(maxBuf)];

    packet = new DatagramPacket(buffer, buffer.length);
    }
    catch (Exception e)
    {
    e.printStackTrace();
    System.out.println("Unable to create UDP Socket");
    throw new Exception("Message thread could not be created");
    }

    setDaemon(true);
    start();
    }

    public void shutdown()
    {
    socket.close();
    }

    public int getLocalPort()
    {
    return socket.getLocalPort();
    }

    public void run()
    {
    System.out.println("Started Message thread. ThreadData = "
    +threadData);
    String args[] = {"Started Message Thread " + threadData};
    browser.call("alert", args);
    boolean stopThread = false;

    readLoop:
    while (!stopThread)
    {
    try
    {
    socket.receive(packet);
    String received = new String(packet.getData(),
    0,packet.getLength());
    processMessage(received);
    }
    catch (SocketException e)
    {
    System.out.println("Shutting up shop");
    stopThread = true;
    continue readLoop;
    }
    catch (IOException e)
    {
    e.printStackTrace();
    System.out.println("Unable to retrieve UDP message");
    }
    }

    System.out.println("Thread run() unit terminating");
    }

    public void processMessage(String msgText)
    {
    int msgType = Integer.parseInt(msgText.substring(0,2));
    switch (msgType){
    case 1:
    chat.append(msgText.substring(2));
    break;
    case 2:
    String args[] = {msgText.substring(2)};
    try {browser.call("priceUpdate", args);}
    catch (JSException e)
    {
    System.out.println("Error when calling
    JSpriceUpdate()");
    }
    break;
    default:
    System.out.println("Unknown rec type"+msgText);
    }
    }
    }

    public void init()
    {
    System.out.println("Initializing. . .");
    hostName = getCodeBase().getHost();

    chat = new Tier3Talk("Tier3 Messages");
    requestFocus();

    browser = JSObject.getWindow(this);

    if (socketThread == null)
    {
    try
    {
    socketThread = new MessageThread("MsgDaemon", "SomeData");
    }
    catch (Exception e)
    {
    e.printStackTrace();
    System.out.println("Could not init Tier3Pager");
    }
    }
    }

    public void alert(String alertText)
    {
    String args[] = {alertText};
    browser.call("alert", args);
    }

    public void destroy()
    {
    if (chat != null)
    chat.dispose();

    boolean stillDying;

    if (socketThread != null){
    socketThread.shutdown();
    do
    {
    stillDying = false;
    System.out.println("Joining MessageThread");
    try {socketThread.join();}
    catch (InterruptedException e){
    System.out.println("Interrupted Join");
    stillDying = true;
    }
    } while (stillDying);

    socketThread = null;
    }

    System.out.println("Tier3Pager Applet Rundown complete");
    super.destroy();
    }
    }


    "Anil" <> wrote in message
    news:...
    > I have a Javascript program which runs in the browser and has
    > functions work(), and stop().
    > It listens to commands from the server to work() and can be
    > interrupted by the server to stop().
    > I am using XmlHttpRequest to talk to the server.
    > So I use http GET to send a command "ready" to the server, which
    > replies at some point in time by sending "work" which is invoked by
    > the callback.
    >
    > As per my understanding, the browser client is single threaded. How to
    > get the server to interrupt the browser client to say "stop"?
    >
    > I modified Flanagan's example code here:
    >
    > var HTTP = {
    >
    > // This is a list of XMLHttpRequest creation factory functions to try
    > _factories : [
    > function() { return new XMLHttpRequest(); },
    > function() { return new ActiveXObject("Msxml2.XMLHTTP"); },
    > function() { return new ActiveXObject("Microsoft.XMLHTTP"); }
    > ],
    >
    > // When we find a factory that works, store it here
    > _factory : null,
    >
    > // Create and return a new XMLHttpRequest object.
    > //
    > // The first time we're called, try the list of factory functions
    > until
    > // we find one that returns a nonnull value and does not throw an
    > // exception. Once we find a working factory, remember it for later
    > use.
    > //
    > newRequest : function() {
    > if (HTTP._factory != null) return HTTP._factory();
    >
    > for(var i = 0; i < HTTP._factories.length; i++) {
    > try {
    > var factory = HTTP._factories;
    > var request = factory();
    > if (request != null) {
    > HTTP._factory = factory;
    > return request;
    > }
    > }
    > catch(e) {
    > continue;
    > }
    > }
    >
    > // If we get here, none of the factory candidates succeeded,
    > // so throw an exception now and for all future calls.
    > HTTP._factory = function() {
    > throw new Error("XMLHttpRequest not supported");
    > }
    > HTTP._factory(); // Throw an error
    > },
    >
    > /**
    > * Use XMLHttpRequest to fetch the contents of the specified URL
    > using
    > * an HTTP GET request. When the response arrives, pass it (as plain
    > * text) to the specified callback function.
    > *
    > * This function does not block and has no return value.
    > */
    > toServer : function(url) {
    > var request = HTTP.newRequest();
    > request.onreadystatechange = function() {
    > if (request.readyState == 4 && request.status == 200)
    > MyProxy.fromServer(request.responseText);
    > }
    > request.open("GET", url, true); // 3rd param implies asynchronous
    > console.log("sending " + url);
    > request.send(null);
    > },
    >
    > };
    >
    > .....
    > // MyProxy
    > ...
    > fromServer: function(command) {
    > console.log("fromServer: " + command);
    > eval(command);
    > },
    > thanks,
    > Anil
    Richard Maher, Nov 3, 2008
    #8
  9. Anil

    Jorge Guest

    On Oct 22, 3:20 pm, Anil <> wrote:
    > (...)
    > In MyProxy.fromServer(), issue another toServer("url").
    > Thus there will always be a GET request pending. Since it is
    > asynchronous, it will return immediately. But the callback will occur
    > while the client is executing.
    >
    > so what happens here - what will the browser do - will it simply
    > block, or a new thread be created? My understanding is stuck here.



    There's just a single thread. No new threads will be created, no,
    never.
    IOW, callback() won't be called until after work() completes.

    Consider this work() function: ("stop" being a global) :

    function work () {
    while (!stop) {
    //keep working
    }
    }

    and this callback():

    function onReadyStateChangeCallBack () {
    if ((xhr.readyState > 3) && (xhr.status === 200)) {
    stop= (xhr.responseText === "stop");
    }
    }

    The above code won't work. The reason is that in order to give a
    chance to the JS interpreter to call onReadyStateChangeCallBack(),
    work() has to complete first, but it won't unless the callBack gets
    called. Therefore it's a deadlock.

    Consider this work() function instead:

    function work () {
    doJustALittleBitOfWorkAtATime();
    if (!stop) {
    setTimeout(arguments.callee, 0)
    }
    }

    Now, work() isn't locked in an endless loop that prevents
    onReadyStateChangeCallBack() to be called: every time work() is re-
    scheduled to run again a.s.a.p. by the setTimeout(work, 0), the
    interpreter has the chance to service any pending callbacks (and it
    will do so before returning to "work").

    HTH,
    --
    Jorge.
    Jorge, Nov 3, 2008
    #9
  10. Anil

    Anil Guest

    On Nov 3, 4:16 am, Jorge <> wrote:
    > On Oct 22, 3:20 pm, Anil <> wrote:
    >
    > > (...)
    > > In MyProxy.fromServer(), issue another toServer("url").
    > > Thus there will always be a GET request pending. Since it is
    > > asynchronous, it will return immediately. But the callback will occur
    > > while the client is executing.

    >
    > > so what happens here - what will the browser do - will it simply
    > > block, or a new thread be created? My understanding is stuck here.

    >
    > There's just a single thread. No new threads will be created, no,
    > never.
    > IOW, callback() won't be called until after work() completes.
    >
    > Consider this work() function: ("stop" being a global) :
    >
    > function work () {
    > while (!stop) {
    > //keep working
    > }
    >
    > }
    >
    > and this callback():
    >
    > function onReadyStateChangeCallBack () {
    > if ((xhr.readyState > 3) && (xhr.status === 200)) {
    > stop= (xhr.responseText === "stop");
    > }
    >
    > }
    >
    > The above code won't work. The reason is that in order to give a
    > chance to the JS interpreter to call onReadyStateChangeCallBack(),
    > work() has to complete first, but it won't unless the callBack gets
    > called. Therefore it's a deadlock.
    >
    > Consider this work() function instead:
    >
    > function work () {
    > doJustALittleBitOfWorkAtATime();
    > if (!stop) {
    > setTimeout(arguments.callee, 0)
    > }
    >
    > }
    >
    > Now, work() isn't locked in an endless loop that prevents
    > onReadyStateChangeCallBack() to be called: every time work() is re-
    > scheduled to run again a.s.a.p. by the setTimeout(work, 0), the
    > interpreter has the chance to service any pending callbacks (and it
    > will do so before returning to "work").
    >
    > HTH,
    > --
    > Jorge.


    Thanks Jorge, I shall try your solution doJustALittleBitOfWorkAtATime
    ();
    It seemed to me that an embedded media player in the browser creates a
    new thread so that things won't block.
    -
    Anil
    Anil, Nov 12, 2008
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Tony
    Replies:
    0
    Views:
    1,034
  2. Replies:
    0
    Views:
    429
  3. -
    Replies:
    2
    Views:
    387
    Alan Krueger
    Jul 29, 2005
  4. Carl
    Replies:
    1
    Views:
    769
    Mathias Waack
    Nov 21, 2004
  5. mani
    Replies:
    3
    Views:
    287
    Default User
    Nov 18, 2007
Loading...

Share This Page