线程化,Web工作者和声明为
的函数之间的区别是什么async function xxx()
{
}
我知道web worker是在不同的线程上执行的,但异步函数呢?这些函数的线程是否与通过setInterval执行的函数相同,或者它们是否受到另一种不同类型的线程的影响?
答案 0 :(得分:9)
Async
函数只是Promises
周围的语法糖,它们是Callbacks
的包装器。所以基本上,当你await
时,JS引擎会继续处理其他事情,直到callback
等待回电。
是否涉及另一个线程取决于您在async
函数中等待的内容。如果它是一个计时器(setTimeout
),则设置一个内部计时器,并且JS线程继续执行其他操作,直到计时器完成,然后继续执行。
这种行为与采取回调或返回promise
的每个函数有些相同。但是其中一些,特别是在Node.js环境中(fetch
,fs.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
示例使用了回调。 Promises
和async
在较低级别以相同的方式工作 - 它们依赖于该消息队列概念,但只是在语法上不同。
答案 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);
}
);