栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

JavaScript和线程

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JavaScript和线程

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

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

有以模拟与异步执行一些哈克的方式产率,

setTimeout()
setInterval()
XMLHttpRequest
或事件处理程序(看到此信息的用于与例如端部收率和
setTimeout()
)。

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

真正的多线程

多线程:Javascript Worker线程

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

这是一个简单的示例,其中包含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/2576706function getscriptPath(foo){ return window.URL.createObjectURL(new Blob([foo.toString().match(/^s*functions*(s*)s*{(([sS](?!}$))*[sS])/)[1]],{type:'text/javascript'})); }var MAX_VALUE = 10000;//Worker 1var 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 pageworker1.addEventListener('message', function(e) {  document.getElementById("result1").innerHTML = e.data;}, false);//Worker 2var 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 3var 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都会执行一个线程。我们可以通过URL 为iframe提供一些参数,并且iframe可以与其父级进行通信以获取结果并将其打印回去(iframe必须位于同一域中)。

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

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

index.html:

//The 3 iframes containing the pre (take the thread id in param)<iframe id="threadframe1" src="https://www.mshxw.com/skin/sinaskin/image/nopic.gif"></iframe><iframe id="threadframe2" src="https://www.mshxw.com/skin/sinaskin/image/nopic.gif"></iframe><iframe id="threadframe3" src="https://www.mshxw.com/skin/sinaskin/image/nopic.gif"></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/2576706function getQueryParams(paramName) {    var qs = document.location.search.split('+').join(' ');    var params = {}, tokens, re = /[?&]?([^=]+)=([^&]*)/g;    while (tokens = re.exec(qs)) {        params[depreURIComponent(tokens[1])] = depreURIComponent(tokens[2]);    }    return params[paramName];}//The thread pre (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(){  }, 0);setTimeout(function(){  }, 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并发

Yield是 ECMAscript 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>


转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/575091.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号