Javascript异步函数和Web worker之间的区别?

时间:2018-03-04 07:20:15

标签: javascript async-await web-worker

线程化,Web工作者和声明为

的函数之间的区别是什么
async function xxx()
{
}

我知道web worker是在不同的线程上执行的,但异步函数呢?这些函数的线程是否与通过setInterval执行的函数相同,或者它们是否受到另一种不同类型的线程的影响?

5 个答案:

答案 0 :(得分:9)

Async函数只是Promises周围的语法糖,它们是Callbacks的包装器。所以基本上,当你await时,JS引擎会继续处理其他事情,直到callback等待回电。

是否涉及另一个线程取决于您在async函数中等待的内容。如果它是一个计时器(setTimeout),则设置一个内部计时器,并且JS线程继续执行其他操作,直到计时器完成,然后继续执行。

这种行为与采取回调或返回promise的每个函数有些相同。但是其中一些,特别是在Node.js环境中(fetchfs.readFile)将在内部启动另一个线程。您只需移交一些参数并在线程完成时接收结果。但是,使用WebWorkers,您可以直接控制另一个线程。对于舒尔,您也可以await来自其他线程的操作:

const workerDone = new Promise(res => window.onmessage = res);

(async function(){
    const result = await workerDone;
        //...
})();

TL; DR:

JS  <---> callbacks / promises <--> internal Thread / Webworker

答案 1 :(得分:7)

WebWorkers相反,async函数永远不能保证在单独的线程上执行。

他们只是在他们的响应到来之前不会阻止整个线程。您可以将它们视为注册为等待的结果,让其他代码执行,当它们的响应通过时它们会被执行;因此名称为异步编程。

这是通过消息队列实现的,消息队列是要处理的消息列表。每条消息都有一个相关的函数,可以调用它来处理消息。

这样做:

setTimeout(() => {
    console.log('foo')
}, 1000)

只会将回调函数(记录到控制台)添加到消息队列中。当1000ms计时器结束时,消息将从消息队列中弹出并执行。

当计时器正在滴答作响时,其他代码可以自由执行。这就是多线程的假象。

上面的setTimeout示例使用了回调。 Promisesasync在较低级别以相同的方式工作 - 它们依赖于该消息队列概念,但只是在语法上不同。

答案 2 :(得分:5)

异步函数与Web worker或节点子进程无关 - 与那些不同,它们不是多线程并行处理的解决方案。

对于返回promise async function链的函数,then()只是 1 语法糖。

async function example() {
    await delay(1000);
    console.log("waited.");
}

相同
function example() {
    return Promise.resolve(delay(1000)).then(() => {
        console.log("waited.");
    });
}

这两个人的行为几乎无法区分。 await的语义或者在promises方面指定的语义,以及每个async function确实会为其结果返回一个承诺。

1:语法糖在存在控制结构(例如if / else或更难以表达的循环时更精细地获得作为一个线性承诺链,但它在概念上仍然是相同的。

  

这些函数的线程是否与通过setInterval执行的函数相同?

是的,async function的异步部分在标准事件循环上运行(承诺)回调。上面示例中的delay将使用普通setTimeout实现 - 包含在易于使用的承诺中:

function delay(t) {
    return new Promise(resolve => {
        setTimeout(resolve, t);
    });
}

答案 3 :(得分:2)

我想在我的问题中添加自己的答案,并通过所有其他人的答案收集理解:

最终,除了网络工作者之外,所有人都会得到美化回调。异步函数中的代码,通过promises调用的函数,通过setInterval调用的函数等等 - 都在主线程中执行,其机制类似于上下文切换。根本不存在并行性。

真正的并行执行及其所有优点和缺陷,仅适用于网络工作者和网络工作者。

(可惜 - 我想过&#34;异步功能&#34;我们最终得到了简化和#34;内联&#34;线程化)

答案 4 :(得分:1)

这是一种将标准函数称为worker的方法,可实现真正的并行性。在撒旦的帮助下,这是一个用血液写成的不圣洁的黑客,可能有大量的浏览器怪癖可以打破它,但据我所知它可行。

[约束:函数标题必须像函数f(a,b,c)一样简单,如果有任何结果,它有通过返回声明]

function Async(func, params, callback)
{ 
 // ACQUIRE ORIGINAL FUNCTION'S CODE
 var text = func.toString(); 


 // EXTRACT ARGUMENTS
 var args = text.slice(text.indexOf("(") + 1, text.indexOf(")")); 
 args     = args.split(",");
 for(arg of args) arg = arg.trim();


 // ALTER FUNCTION'S CODE:
 // 1) DECLARE ARGUMENTS AS VARIABLES
 // 2) REPLACE RETURN STATEMENTS WITH THREAD POSTMESSAGE AND TERMINATION
 var body = text.slice(text.indexOf("{") + 1, text.lastIndexOf("}")); 
 for(var i = 0, c = params.length; i<c; i++) body = "var " + args[i] + " = " + JSON.stringify(params[i]) + ";" + body;
 body = body + " self.close();"; 
 body = body.replace(/return\s+([^;]*);/g, 'self.postMessage($1); self.close();');


 // CREATE THE WORKER FROM FUNCTION'S ALTERED CODE
 var code   = URL.createObjectURL(new Blob([body], {type:"text/javascript"}));
 var thread = new Worker(code);


 // WHEN THE WORKER SENDS BACK A RESULT, CALLBACK AND TERMINATE THE THREAD
 thread.onmessage =
 function(result)
 {
  if(callback) callback(result.data);

  thread.terminate();
 }

}

所以,假设你有这个潜在的cpu密集型函数......

function HeavyWorkload(nx, ny) 
{
 var data = [];

 for(var x = 0; x < nx; x++)
 {
  data[x] = [];

  for(var y = 0; y < ny; y++)
  {
   data[x][y] = Math.random();
  }
 }

 return data;
}

...你现在可以这样称呼它:

Async(HeavyWorkload, [1000, 1000],
function(result)
{
 console.log(result);
}
);