JavaScript和线程

2020/11/18 09:42 · javascript ·  · 0评论

有没有办法在JavaScript中进行多线程处理?

有关最新的支持信息,请参见http://caniuse.com/#search=worker

以下是大约2009年的支持情况。


您要搜索的单词是JavaScript Worker线程

除了Gears之外,目前没有任何可用的东西,但是关于如何实现这一点的讨论很多,所以我想注意这个问题,因为答案无疑会在未来发生变化。

以下是Gears的相关文档:WorkerPool API

WHATWG有一个针对工作线程的建议草案:Web Workers

还有Mozilla的DOM Worker线程


更新: 2009年6月,浏览器对JavaScript线程支持的当前状态

Firefox 3.5具有网络工作者。如果您想看到网络工作者的一些演示,请执行以下操作:

Gears插件也可以安装在Firefox中。

Safari 4WebKit每晚都有工作线程:

Chrome已加入Gears,因此可以执行线程操作,尽管它需要用户确认提示(并且它使用与Web Worker不同的API,尽管它可以在安装了Gears插件的任何浏览器中使用):

  • Google Gears WorkerPool演示(不是一个很好的例子,因为它运行速度太快,无法在Chrome和Firefox中进行测试,尽管IE的运行速度足够慢,以至于它阻止了交互)

IE8IE9只能在安装Gears插件的情况下执行线程

在JavaScript中执行多线程和异步的不同方法

在HTML5之前,JavaScript仅允许每页执行一个线程。

有以模拟与异步执行一些哈克的方式产率setTimeout()setInterval()XMLHttpRequest事件处理程序(看到此信息的用于与例如端部收率setTimeout())。

但是,借助HTML5,我们现在可以使用工作线程来并行执行功能。这是一个使用示例。


真正的多线程

多线程:JavaScript Worker线程

HTML5引入了Web Worker Threads(请参阅:浏览器兼容性

注意:IE9和更早版本不支持它。

这些工作线程是在后台运行而不会影响页面性能的JavaScript线程。有关Web Worker的 更多信息,请阅读文档本教程

这是一个简单的示例,其中包含3个Web Worker线程,其计数为MAX_VALUE,并在我们的页面中显示当前的计算值:

//As a worker normally take another JavaScript file to execute we convert the function in an URL: http://stackoverflow.com/a/16799132/2576706
function getScriptPath(foo){ return window.URL.createObjectURL(new Blob([foo.toString().match(/^\s*function\s*\(\s*\)\s*\{(([\s\S](?!\}$))*[\s\S])/)[1]],{type:'text/javascript'})); }

var MAX_VALUE = 10000;

/*
 *	Here are the workers
 */
//Worker 1
var worker1 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
//We add a listener to the worker to get the response and show it in the page
worker1.addEventListener('message', function(e) {
  document.getElementById("result1").innerHTML = e.data;
}, false);


//Worker 2
var worker2 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
worker2.addEventListener('message', function(e) {
  document.getElementById("result2").innerHTML = e.data;
}, false);


//Worker 3
var worker3 = new Worker(getScriptPath(function(){
    self.addEventListener('message', function(e) {
        var value = 0;
        while(value <= e.data){
            self.postMessage(value);
            value++;
        }
    }, false);
}));
worker3.addEventListener('message', function(e) {
    document.getElementById("result3").innerHTML = e.data;
}, false);


// Start and send data to our worker.
worker1.postMessage(MAX_VALUE); 
worker2.postMessage(MAX_VALUE); 
worker3.postMessage(MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

我们可以看到这三个线程是并发执行的,并在页面中打印它们的当前值。它们不会冻结页面,因为它们是在后台用单独的线程执行的。


多线程:具有多个iframe

实现此目的的另一种方法是使用多个iframe,每个iframe都会执行一个线程。我们可以通过URLiframe提供一些参数,并且iframe可以与其父级进行通信以获取结果并将其打印回去(iframe必须位于同一域中)。

此示例不适用于所有浏览器! iframe通常与主页在同一线程/进程中运行(但Firefox和Chromium似乎处理方式有所不同)。

由于代码段不支持多个HTML文件,因此我将在此处提供不同的代码:

index.html:

//The 3 iframes containing the code (take the thread id in param)
<iframe id="threadFrame1" src="thread.html?id=1"></iframe>
<iframe id="threadFrame2" src="thread.html?id=2"></iframe>
<iframe id="threadFrame3" src="thread.html?id=3"></iframe>

//Divs that shows the result
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>


<script>
    //This function is called by each iframe
    function threadResult(threadId, result) {
        document.getElementById("result" + threadId).innerHTML = result;
    }
</script>

thread.html:

//Get the parameters in the URL: http://stackoverflow.com/a/1099670/2576706
function getQueryParams(paramName) {
    var qs = document.location.search.split('+').join(' ');
    var params = {}, tokens, re = /[?&]?([^=]+)=([^&]*)/g;
    while (tokens = re.exec(qs)) {
        params[decodeURIComponent(tokens[1])] = decodeURIComponent(tokens[2]);
    }
    return params[paramName];
}

//The thread code (get the id from the URL, we can pass other parameters as needed)
var MAX_VALUE = 100000;
(function thread() {
    var threadId = getQueryParams('id');
    for(var i=0; i<MAX_VALUE; i++){
        parent.threadResult(threadId, i);
    }
})();

模拟多线程

单线程:使用setTimeout()模拟JavaScript并发

“幼稚”的方式是setTimeout()像下面这样一个接一个地执行函数

setTimeout(function(){ /* Some tasks */ }, 0);
setTimeout(function(){ /* Some tasks */ }, 0);
[...]

但是此方法不起作用,因为每个任务都会一个接一个地执行。

我们可以通过递归调用函数来模拟异步执行,如下所示:

var MAX_VALUE = 10000;

function thread1(value, maxValue){
    var me = this;
    document.getElementById("result1").innerHTML = value;
    value++;
  
    //Continue execution
    if(value<=maxValue)
        setTimeout(function () { me.thread1(value, maxValue); }, 0);
}

function thread2(value, maxValue){
    var me = this;
    document.getElementById("result2").innerHTML = value;
    value++;
	
    if(value<=maxValue)
        setTimeout(function () { me.thread2(value, maxValue); }, 0);
}

function thread3(value, maxValue){
    var me = this;
    document.getElementById("result3").innerHTML = value;
    value++;
	
    if(value<=maxValue)
        setTimeout(function () { me.thread3(value, maxValue); }, 0);
}

thread1(0, MAX_VALUE);
thread2(0, MAX_VALUE);
thread3(0, MAX_VALUE);
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

如您所见,第二种方法非常慢并且冻结了浏览器,因为它使用主线程来执行功能。


单线程:使用yield模拟JavaScript并发

YieldECMAScript 6中的一项新功能,仅适用于Firefox和Chrome的最旧版本(在Chrome中,您需要启用出现在chrome:// flags /#enable-javascript-harmony中的实验性JavaScript)。

yield关键字使生成器函数的执行暂停,并且yield关键字之后的表达式的值将返回到生成器的调用者。可以将其视为return关键字的基于生成器的版本。

生成器使您可以中止函数的执行并在以后继续执行。生成器可用于通过称为蹦床的技术来安排您的功能

这是示例:

var MAX_VALUE = 10000;

Scheduler = {
	_tasks: [],
	add: function(func){
		this._tasks.push(func);
	},	
	start: function(){
		var tasks = this._tasks;
		var length = tasks.length;
		while(length>0){
			for(var i=0; i<length; i++){
				var res = tasks[i].next();
				if(res.done){
					tasks.splice(i, 1);
					length--;
					i--;
				}
			}
		}
	}	
}


function* updateUI(threadID, maxValue) {
  var value = 0;
  while(value<=maxValue){
	yield document.getElementById("result" + threadID).innerHTML = value;
	value++;
  }
}

Scheduler.add(updateUI(1, MAX_VALUE));
Scheduler.add(updateUI(2, MAX_VALUE));
Scheduler.add(updateUI(3, MAX_VALUE));

Scheduler.start()
<div id="result1"></div>
<div id="result2"></div>
<div id="result3"></div>

使用HTML5“附带规范”,不再需要使用setTimeout(),setInterval()等来入侵JavaScript

HTML5&Friends引入了javascript Web Workers规范。它是用于异步独立运行脚本的API。

链接到规范教程

JavaScript中没有真正的线程。JavaScript是它的可扩展语言,它确实允许您模仿其中的一些。这是我前几天遇到的一个例子

Javascript中没有真正的多线程,但是您可以使用setTimeout()异步AJAX请求获得异步行为

您到底想完成什么?

这只是在Javascript中模拟多线程的一种方法

现在,我将创建3个线程来计算数字加法,可以将数字除以13,然后将数字除以3,直到10000000000。这3个函数不能与并发性同时运行。但是,我将向您展示一个使这些函数在同一时间递归运行的技巧:jsFiddle

这段代码属于我。

身体的一部分

    <div class="div1">
    <input type="button" value="start/stop" onclick="_thread1.control ? _thread1.stop() : _thread1.start();" /><span>Counting summation of numbers till 10000000000</span> = <span id="1">0</span>
</div>
<div class="div2">
    <input type="button" value="start/stop" onclick="_thread2.control ? _thread2.stop() : _thread2.start();" /><span>Counting numbers can be divided with 13 till 10000000000</span> = <span id="2">0</span>
</div>
<div class="div3">
    <input type="button" value="start/stop" onclick="_thread3.control ? _thread3.stop() : _thread3.start();" /><span>Counting numbers can be divided with 3 till 10000000000</span> = <span id="3">0</span>
</div>

Javascript部分

var _thread1 = {//This is my thread as object
    control: false,//this is my control that will be used for start stop
    value: 0, //stores my result
    current: 0, //stores current number
    func: function () {   //this is my func that will run
        if (this.control) {      // checking for control to run
            if (this.current < 10000000000) {
                this.value += this.current;   
                document.getElementById("1").innerHTML = this.value;
                this.current++;
            }
        }
        setTimeout(function () {  // And here is the trick! setTimeout is a king that will help us simulate threading in javascript
            _thread1.func();    //You cannot use this.func() just try to call with your object name
        }, 0);
    },
    start: function () {
        this.control = true;   //start function
    },
    stop: function () {
        this.control = false;    //stop function
    },
    init: function () {
        setTimeout(function () {
            _thread1.func();    // the first call of our thread
        }, 0)
    }
};
var _thread2 = {
    control: false,
    value: 0,
    current: 0,
    func: function () {
        if (this.control) {
            if (this.current % 13 == 0) {
                this.value++;
            }
            this.current++;
            document.getElementById("2").innerHTML = this.value;
        }
        setTimeout(function () {
            _thread2.func();
        }, 0);
    },
    start: function () {
        this.control = true;
    },
    stop: function () {
        this.control = false;
    },
    init: function () {
        setTimeout(function () {
            _thread2.func();
        }, 0)
    }
};
var _thread3 = {
    control: false,
    value: 0,
    current: 0,
    func: function () {
        if (this.control) {
            if (this.current % 3 == 0) {
                this.value++;
            }
            this.current++;
            document.getElementById("3").innerHTML = this.value;
        }
        setTimeout(function () {
            _thread3.func();
        }, 0);
    },
    start: function () {
        this.control = true;
    },
    stop: function () {
        this.control = false;
    },
    init: function () {
        setTimeout(function () {
            _thread3.func();
        }, 0)
    }
};

_thread1.init();
_thread2.init();
_thread3.init();

我希望这种方式会有所帮助。

您可以使用Narrative JavaScript,这是一种编译器,可以将您的代码转换为状态机,从而有效地模拟线程。通过在允许您在单个线性代码块中编写异步代码的语言中添加“屈服”运算符(表示为“->”)来实现此目的。

今天应该发布的新v8引擎支持它(我认为)

在原始Javascript中,您可以做的最好的事情就是使用几个异步调用(xmlhttprequest),但这并不是真正的线程化,而且非常有限。 Google Gears向浏览器添加了许多API,其中一些可用于线程支持。

如果您不能或不想使用任何AJAX内容,请使用iframe或10!;)您可以使进程在与母版页并行的iframe中运行,而不必担心跨浏览器的可比问题或点网AJAX等的语法问题,并且可以从iframe。

例如,在父iframe中,egFunction()一旦iframe内容已加载(这是异步部分),就调用父文档

parent.egFunction();

也可以动态生成iframe,因此如果需要的话,主要的html代码也可以免费使用。

另一种可能的方法是在javascript环境中使用javascript解释器。

通过创建多个解释器并从主线程控制它们的执行,您可以在每个线程在其各自的环境中运行的情况下模拟多线程。

这种方法有点类似于Web Worker,但是您可以让解释器访问浏览器的全局环境。

我做了一个小项目来证明这一点

此博客文章中有更详细的解释

Javascript没有线程,但是我们有工人。

如果不需要共享对象,则工作者可能是一个不错的选择。

实际上,大多数浏览器实现会将工作人员分布在所有内核上,从而使您可以利用所有内核。您可以在此处查看此演示

我已经开发了一个名为task.js的库,它使此操作非常容易。

task.js简化的界面,用于使CPU密集型代码在所有内核(node.js和Web)上运行

一个例子是

function blocking (exampleArgument) {
    // block thread
}

// turn blocking pure function into a worker task
const blockingAsync = task.wrap(blocking);

// run task on a autoscaling worker pool
blockingAsync('exampleArgumentValue').then(result => {
    // do something with result
});

With HTML5 specification you do not need to write too much JS for the same or find some hacks.

One of the feature introduced in HTML5 is Web Workers which is JavaScript running in the background,independently of other scripts, without affecting the performance of the page.

It is supported in almost all browsers :

Chrome - 4.0+

IE - 10.0+

Mozilla - 3.5+

Safari - 4.0+

Opera - 11.5+

本文地址:http://javascript.askforanswer.com/javascripthexiancheng.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!