This project has moved. For the latest updates, please go here.

will this code work with jurassic ?

Jan 23, 2012 at 5:52 PM

   Can You review my code ? Also if you want you can include it in source code of Jurassic. Thats my contribution. Thanks

    /*       

var worker = new Worker("worker.js");  // Watch for messages from the worker        
worker.onmessage = function(e){     
Debug.writeln (e.data);   
};

    worker.postMessage("start");


    The file worker.js:


    onmessage = function(e){     
if ( e.data === "start" ) {                      
for (var i = 0; i < 999999; i++); // Do some computation                
postMessage("done"); // Send back the results to the parent page     
}   
};                

*/

public class WorkerConstructor : ClrFunction   
{       
public WorkerConstructor(ScriptEngine engine)           
: base(engine.Function.InstancePrototype, "Worker", new WorkerInstance (engine.Object.InstancePrototype))       
{       
}

        [JSConstructorFunction]       
public WorkerInstance Construct(string source_file)       
{           
return new WorkerInstance(this.InstancePrototype, source_file);       
}   
}

public class WorkerInstance : ObjectInstance    
{       
ScriptEngine WorkerEngine;       
Task Task1;       
Task Task2;

        public WorkerInstance(ObjectInstance prototype) : base(prototype)       
{           
this.PopulateFunctions();       
}

        public WorkerInstance (ObjectInstance prototype, string source_file) : base(prototype)       
{           
Task1 = Task.Factory.StartNew(() =>            
{               
WorkerEngine = new Jurassic.ScriptEngine();

                WorkerEngine.SetGlobalFunction("postMessgae",                   
new Action<ObjectInstance>(message =>                   
{                       
this.CallMemberFunction("onmessage", message);                   
}));


                WorkerEngine.ExecuteFile(source_file as string);           
});

            Task1.Start();       
}

        [JSFunction(Name = "postMessgae")]       
public void PostMessgae (ObjectInstance message)       
{           

Task1.Wait();

            Task2 = Task.Factory.StartNew(() =>           
{               
WorkerEngine.CallGlobalFunction("onmessage", message);           
});                       

Task2.Start();       
}   
}

Coordinator
Jan 29, 2012 at 8:03 PM

Thanks - I can't use this as-is, because I want to support .NET 3.5, but I'm definitely interested in implementing web workers into Jurassic.

Here's my feedback:

  • You misspelt "postMessgae"
  • PostMessage is async, i.e. it returns immediately.  If PostMessage is called multiple times in quick succession the ScriptEngine object could be called concurrently, which is not safe.  PostMessage needs to ensure that the WorkerEngine instance is not being called.  Either wait on Task2 or queue the messages until they can be delivered.
Jan 29, 2012 at 9:24 PM
I have a working implementation (I think) of webworkers over at https://github.com/Alxandr/RunJS/blob/master/src/RunJS.Core/JsWorker.cs
However, it's a bit coupled.
--
/Alxandr
Jan 30, 2012 at 4:49 PM

Thansk. Lets try again. And what about this (net 3.5 version, with jsno serializing) ?

    /*        var worker = new Worker("worker.js");  // Watch for messages from the worker        

               worker.onmessage = function(e) {      Debug.writeln (e.data);    };

                worker.postMessage("start");


    The file worker.js:

                  onmessage = function(e)
                  {     
                            if ( e.data === "start" )
                            {                      
                                  for (var i = 0; i < 999999; i++); // Do some computation                

                                  postMessage("done"); // Send back the results to the parent page     
                            }   
                   };     


*/      

public class WorkerConstructor : ClrFunction   
{       
    public WorkerConstructor(ScriptEngine engine)           
               : base(engine.Function.InstancePrototype, "Worker", new WorkerInstance (engine.Object.InstancePrototype))       
    {       
    }

    [JSConstructorFunction]
    public WorkerInstance Construct(string source_file)       
    {           
              return new WorkerInstance(this.InstancePrototype, source_file);       
    }   

}

public class WorkerInstance : ObjectInstance    
{       
        // Child Engine that works in another tread.
        ScriptEngine WorkerEngine = null;

        public WorkerInstance(ObjectInstance prototype) : base(prototype) { this.PopulateFunctions();  }

        // Initialize WorkerEngine with source provided by WebWorker constructor
        private void RunTask1 (object source)       
        {           
lock (WorkerEngine)           
{               
WorkerEngine.ExecuteFile(source as string);           
}       
}

        // WebWorker constructor
        public WorkerInstance (ObjectInstance prototype, string source_file) : base(prototype)       
{           
WorkerEngine = new Jurassic.ScriptEngine();

            WorkerEngine.SetGlobalFunction("postMessge", new Action<ObjectInstance>(DoWorkerEnginePostMessge));

            Thread Task1 = new Thread(new ParameterizedThreadStart(RunTask1));

            Task1.Start(source_file);       
}

        private void DoWorkerEnginePostMessge(ObjectInstance message)       
{           
string str_msg = JSONObject.Stringify(WorkerEngine, message); // Avoid one engine to use an objectInstance fromother serializing to JSON 

            lock (this.Engine) // Prevents Parents engine reentration           
{               
object onj_msg = JSONObject.Parse(this.Engine, str_msg);

                this.CallMemberFunction("onmessage", message);           
}       
}

        private void RunTask2(object msg)       
{           
lock (WorkerEngine) // Prevents Child engine reentration           
{               
object obj_message = JSONObject.Parse (WorkerEngine, (msg as string));

                WorkerEngine.CallGlobalFunction("onmessage", obj_message);           
}       
}


        [JSFunction(Name = "postMessge")]       
public void PostMessge (ObjectInstance message)       
{           
string str_message = JSONObject.Stringify (this.Engine, message);            

Thread Task2 = new Thread(new ParameterizedThreadStart(RunTask2));                      

Task2.Start(str_message);       
}   
}