1 javascript web-worker promise
在现代浏览器中运行的 Javascript 中,我希望对函数进行非阻塞调用。
有人指出 Promises 以及构建在它们之上的异步函数,但我发现 Promises(以及异步函数)确实会阻塞。请参阅下面的代码来演示这一点。
唯一不阻塞的函数似乎是内置的。例如 setTimeout。这似乎就是我发现的所有“非阻塞”Promise 示例都使用 setTimeout 的原因。执行的单个线程会遍历超时代码并调用非阻塞 setTimeout,以便继续执行。Promise 本身只是组织回调,这很好,但它们本身并不会导致调用非阻塞。
webworker 解决方案似乎没有引用,因此无法修改调用者的数据。序列化、调用网络工作者,然后反序列化以获取结果将是相当低效且复杂的。
这是从 Promise 获取“非阻塞”行为的典型示例,但如果您在 Web 控制台中单步执行它,您将看到唯一不阻塞的是 setTimeout。
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
</head>
<body>
<script>
'use strict';
function wait_setTimeout(call_when_finished){
console.log("entering wait_setTimeout");
setTimeout(call_when_finished, 2000); // 3 second delay
}
function wait_setTimeout_resolve(){
console.log("wait_setTimeout_resolved");
}
console.log("before wait_setTimeout promise");
let p0 = new Promise((wait_setTimeout_resolve) => {
this.wait_setTimeout(wait_setTimeout_resolve);
});
console.log("after new Promise(wait_setTimeout_resolve)");
p0.then(() => console.log("then wait_setTimeout_promise target"));
console.log("after wait_setTimeout_promise.then");
/*
before wait_setTimeout promise
entering wait_setTimeout
after new Promise(wait_setTimeout_resolve)
after wait_setTimeout_promise.then
<delay occurs here, as it should, but because setTimeout didn't block, not the Promise>
then wait_setTimeout_promise target
*/
</script>
</body>
Run Code Online (Sandbox Code Playgroud)
相反,如果我们用循环创建时间延迟,很明显 Promise 会阻塞:
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
</head>
<body>
<script>
'use strict';
let limit = 100000; // ~3 second delay, make this bigger if you don't see a delay
function wait_loop(call_when_finished){
console.log("entering wait_loop");
let i = 0;
let j;
while(i < limit){
i++;
j = 0;
while(j < limit){
j++;
}}
call_when_finished();
}
function wait_loop_resolve(){
console.log("wait_loop_resolved");
}
console.log("before wait_loop promise");
let p1 = new Promise((wait_loop_resolve) => {
this.wait_loop(wait_loop_resolve);
});
console.log("after new Promise(wait_loop_resolve)");
p1.then(() => console.log("then wait_loop_promise target"));
console.log("after wait_loop_promise.then");
/*
before wait_loop promise
entering wait_loop
<delay occurs here.. i.e. the new Promise blocked>
after new Promise(wait_loop_resolve)
after wait_loop_promise.then
then wait_loop_promise target
*/
</script>
</body>
Run Code Online (Sandbox Code Playgroud)
当然循环只是一个占位符。实际的代码正在计算所需的东西。
Promise 不是线程,JS 很大程度上是单线程的,并且在事件队列中工作。事实上,promise 只是组织回调。
如果您想运行 CPU 密集型代码,那么您需要使用Web Workers,并使用它们的接口与它们进行通信postMessage(如果您愿意,可以将其包装成 Promise 返回格式)。它们确实作为在单独线程上运行的脚本运行,但请注意它们的通信是如何受到限制的,它不像经典的多线程那样自由支配内存访问。
Web Workers 将无权访问您的窗口,因此不会对其中的 DOM 进行修改。但是,如果您有复杂的模拟,您可以巧妙地将数据模型与显示分开,只需将数据模型传输到工作人员或从工作人员传出数据模型,然后使用普通脚本将其转换为 UI。
要了解有关 JavaScript 执行模型的更多信息,我建议您参阅MDN 上的介绍,如果您想深入了解其实现方式,请参阅 Jake Archibald 的演示文稿。
| 归档时间: |
|
| 查看次数: |
2372 次 |
| 最近记录: |