Research on Web worker multi-thread API in JavaScript, workerapi
HTML5 supports APIs such as Web Worker, allowing Web pages to execute multi-threaded code securely. However, Web Worker is actually subject to many restrictions because it cannot truly share memory data and can only use messages for status notifications. Therefore, it cannot even be called a real "multi-thread ".
The Web Worker interface is inconvenient to use. It basically comes with a sandbox that runs an independent js file in the sandbox and communicates with the main thread through postMessage and onMessge:
Copy codeThe Code is as follows:
Var worker = new Worker ("my. js ");
Var bundle = {message: 'Hello world', id: 1 };
Worker. postMessage (bundle); // postMessage can pass a serializable object to the past
Worker. onmessage = function (evt ){
Console. log (evt. data); // compares the objects returned by worker with the objects in the main thread.
Console. log (bundle); // {message: 'Hello world', id: 1}
}
Copy codeThe Code is as follows:
// In my. js
Onmessage = function (evt ){
Var data = evt. data;
Data. id ++;
PostMessage (data); // {message: 'Hello world', id: 2}
}
The result shows that the data id in the thread is increased, but after the data is passed back, the id in the bundle of the main thread is not changed. Therefore, the object passed in the thread is actually copied. In this way, the thread does not share data, avoiding read/write conflicts, so it is safe. The cost of ensuring thread security is to limit the ability to operate the main thread object in the thread.
It is inconvenient to use such a limited multi-threaded mechanism. We certainly hope that Worker can support the ability to make code seem to have the ability to operate multiple threads at the same time. For example, it supports code that looks like the following:
Copy codeThe Code is as follows:
Var worker = new ThreadWorker (bundle/* shared obj */);
Worker. run (function (bundle ){
// Do something in worker thread...
This. runOnUiThread (function (bundle/* shared obj */){
// Do something in main ui thread...
});
//...
});
In this Code, after we start a worker, we can run any code in the worker, and when we need to operate the ui thread (such as reading and writing dom), we can use this. runOnUiThread is returned to the main thread for execution.
How can this mechanism be implemented? See the following code:
Copy codeThe Code is as follows:
Function WorkerThread (mongodobj ){
This. _ worker = new Worker ("thread. js ");
This. _ completes = {};
This. _ task_id = 0;
This. Export dobj = export dobj;
Var self = this;
This. _ worker. onmessage = function (evt ){
Var ret = evt. data;
If (ret. _ UI_TASK __){
// Run on ui task
Var fn = (new Function ("return" + ret. _ UI_TASK __))();
Fn (ret. ret dobj );
} Else {
Self. Empty dobj = ret. Empty dobj;
Self. _ completes [ret. taskId] (ret );
}
}
}
WorkerThread. prototype. run = function (task, complete ){
Var _ task = {__ THREAD_TASK __: task. toString (), export dobj: this. Export dobj, taskId: this. _ task_id };
This. _ completes [this. _ task_id ++] = complete;
This. _ worker. postMessage (_ task );
}
The above Code defines a ThreadWorker object, which creates a Web Worker running thread. js, saves the shared object mongodobj, and processes the messages sent back by thread. js.
If a UI_TASK message is returned in thread. js, run the function passed in the message. Otherwise, run the complete callback of run to see how thread. js is written:
Copy codeThe Code is as follows:
Onmessage = function (evt ){
Var data = evt. data;
If (data & data. _ THREAD_TASK __){
Var task = data. _ THREAD_TASK __;
Try {
Var fn = (new Function ("return" + task ))();
Var ctx = {
ThreadSignal: true,
Sleep: function (interval ){
Ctx. threadSignal = false;
SetTimeout (_ run, interval );
},
RunOnUiThread: function (task ){
PostMessage ({__ UI_TASK __: task. toString (), export dobj: data. Export dobj });
}
}
Function _ run (){
Ctx. threadSignal = true;
Var ret = fn. call (ctx, data. Export dobj );
PostMessage ({error: null, returnValue: ret, _ THREAD_TASK __: task, export dobj: data. Export dobj, taskId: data. taskId });
}
_ Run (0 );
} Catch (ex ){
PostMessage ({error: ex. toString (), returnValue: null, export dobj: data. Export dobj });
}
}
}
We can see that thread. js receives messages sent from the ui thread, the most important of which is THREAD_TASK. This is a "task" that the ui thread transfers and requires the worker thread to execute. Because the function is not serializable, therefore, a string is passed. The worker thread parses the string into a function to execute the task submitted by the main thread (note that the shared object mongodobj is passed in the task ), after the execution is complete, the returned results are sent to the ui thread through message. In addition to the returned returnValue value, the shared object mongodobj will also be returned, because the worker thread and ui thread do not share the object, therefore, we manually synchronize objects on both sides by assigning values (is this thread safe? Why ?)
It can be seen that the entire process is not complex. After implementation, this ThreadWorker can be used in the following two ways:
Copy codeThe Code is as follows:
Var t1 = new WorkerThread ({I: 100}/* shared obj */);
SetInterval (function (){
T1.run (function (mongodobj ){
Return response dobj. I ++;
},
Function (r ){
Console. log ("t1>" + r. returnValue + ":" + r. error );
}
);
},500 );
Var t2 = new WorkerThread ({I: 50 });
T2.run (function (mongodobj ){
While (this. threadSignal ){
Export dobj. I ++;
This. runOnUiThread (function (mongodobj ){
W ("body ul"). appendChild ("<li>" + export dobj. I + "</li> ");
});
This. sleep (500 );
}
Return response dobj. I;
}, Function (r ){
Console. log ("t2>" + r. returnValue + ":" + r. error );
});
In terms of form and semantics, such usage gives the Code a good structure, flexibility, and maintainability.
Well, the usage of Web Worker is introduced here, interested students can look at this project: https://github.com/akira-cn/WorkerThread.js (because Worker needs to use server testing, I put httpd in the project. js is a very simple http service js, which can be run directly with node ).