1.前言
javascript众所周知是单线程的语言,但是我们可以通过某些特殊方式来实现多线程的效果。目前我能想到的有两种方式:1.通过微任务计时器实现,2.通过whatwg定义的html5标准的worker线程来实现,下面我们来看下这两种方式的介绍吧。
2.微任务计时器版的多线程实现
多线程可以通过计时器来完成,但是计时器有缺陷,那就是执行优先级比较低,需要等待主线程执行完所有代码才会运行计时器任务,如何遇到主线程阻塞,那么计时器永远也无法执行,下面来看个例子。
var num = 0;
function Task() {
this.taskId = undefined;
this.doTask = function(callback, timeout=1000) {
this.taskId = setInterval(callback,timeout);
return this;
};
this.finishTask = function() {
return clearInterval(this.taskId);
}
}
function TaskPool(max, timeout=1000) {
this.taskObjs = [];
this.taskQueue = [];
this.max = max;
this.num = 0;
this.callback = undefined;
this.timeout = timeout;
this.pushTask = function(callback, identify) {
this.taskQueue.push({callback:callback, identify:identify});
};
this.run = function() {
let that = this;
while(this.taskQueue.length > 0) {
if (this.num++ < max) {
!function doTask(){
//这里是异步的操作,任务队列会先弹出所有任务然后再执行任务
let task = that.taskQueue.pop();
let identify = task.identify;
let callback = task.callback;
that.taskObjs.push({identify:identify, task: new Task().doTask(callback)});
}();
} else {
console.error('主线程无限循环,定时器微任务永远没有执行权限');
}
}
};
this.finishTask = function(identify) {
let found = this.taskObjs.find(function(task) {
return task.identify === identify;
});
if (found) {
found.task.finishTask();
--this.num;
}
}
}
let a = new TaskPool(2); // 任务数量超过队列上限时,主线程会无限循环而定时器则拿不到执行权
a.pushTask(function(){
console.log(num++, 'task1');
if (num > 10) {
a.finishTask('task1');
console.log('finished task1');
}
}, 'task1');
a.pushTask(function(){
console.log(num++, 'task2');
if (num > 20) {
a.finishTask('task2');
console.log('finished task2');
}
}, 'task2');
a.run();

使用计时器函数是异步操作,上面的例子中,如果任务数量超过任务池的最大值,那么会陷入死循环中。
3.worker后台线程的多线程实现
worker后台线程是whatwg定义的web api,2019年以后html的标准控制权已经从W3C转到了whatwg,所以之后的html标准我们都以whatwg的为准。
let workerNums = 5;
var data = 0;
let finished = workerNums;
for(let i = 0; i < workerNums; i ++) {
let worker = new Worker('worker.js');
worker.postMessage(data + i * 10);
worker.onmessage = function(e) {
data = e.data;
if (--finished <= 0) {
console.log('finished');
}
}
}
var count = 0;
onmessage = function(e) {
console.log('worker:' + e.data);
var temp = e.data;
while(count++ < 10) {
console.log(temp++);
}
postMessage(temp);
close();
}

4.两种方式的缺陷
1.定时器实现的多线程是异步的任务,执行前需要等待主线程执行完才能执行。
2.worker后台线程的多线程无法共享数据,只能将数据分片,然后再进行分片处理。
5.参考
如无特殊说明,文章均为本站原创,转载请注明出处。如发现有什么不对的地方,希望得到您的指点。https://html.spec.whatwg.org/multipage/workers.html#introduction-14