Javascript 为什么Promise对象会阻止渲染?
我正在测试Promise对象,并编写了一些代码来模拟长时间运行的同步任务。我在比较Promise和setTimeout-参见:Javascript 为什么Promise对象会阻止渲染?,javascript,promise,settimeout,es6-promise,Javascript,Promise,Settimeout,Es6 Promise,我正在测试Promise对象,并编写了一些代码来模拟长时间运行的同步任务。我在比较Promise和setTimeout-参见: 承诺vs设置超时 使用慢速运行功能设置超时 承诺和慢速运行功能 明确的结果 结果 常数慢=函数(){ 设nu=Date.now(); 而(Date.now()-nu新承诺(解析=>{ 慢(); 解决(); }); const resultsElement=document.getElementById('result') 常量日志=(消息)=>{ resultElem
承诺vs设置超时
使用慢速运行功能设置超时
承诺和慢速运行功能
明确的结果
结果
常数慢=函数(){
设nu=Date.now();
而(Date.now()-nu<1000){}
}
const getSlowPromise=()=>新承诺(解析=>{
慢();
解决();
});
const resultsElement=document.getElementById('result')
常量日志=(消息)=>{
resultElement.innerText+=消息;
}
const setTimeExputton=document.getElementById('settimeout-test');
SetTimeExputton.addEventListener('单击',()=>{
const now=Date.now();
日志(`\nsetTimeout测试在${Date.now()-now}ms`之后开始);
设置超时(()=>{
慢();
log(`\n low函数在${Date.now()-now}ms`之后完成);
}, 0);
日志(`\nEvent listener在${Date.now()-now}ms`之后完成);
});
const promiseButton=document.getElementById('promise-test');
promiseButton.addEventListener('单击',()=>{
const now=Date.now();
日志(`\nsetTimeout测试在${Date.now()-now}ms`之后开始);
getSlowPromise().then(res=>log(`\n promise在${Date.now()-now}ms`)之后完成);
日志(`\nevent listener在${Date.now()-now}ms`之后完成);
})
const clear=()=>resultElement.innerText='';
const clearButton=document.getElementById('clear');
addEventListener('click',()=>clear());
我认为Promise和setTimeout的行为类似,将代码添加到任务队列中,然后继续执行。结果的顺序是相同的,但长时间运行的任务的承诺似乎会阻止渲染,直到长时间运行的任务完成。有人能解释一下吗
该示例在Chrome中运行得最好
更新:
我并不是想让长时间运行的任务并行运行,我只是想了解为什么Promise和setTimeout在我的示例中表现不同。但是,如果您确实希望并行运行任务,那么Web工作者/工作者线程就是昆汀建议的方法
但我的问题的答案似乎是,正如Bergi在评论中所写,Promise构造函数是同步的。
这里有一个较长的,而(Date.now()-nu<1000){}
不模拟同步的长时间运行的任务。它是一个同步的长时间运行的任务
承诺是一种管理异步代码的方法,而不是使代码异步的方法,也不是模拟多线程的方法
为此,你需要看看工人
- 对于浏览器
- 对于Node.js
while(Date.now()-nu<1000){}
阻止渲染-承诺不会魔术般地消除同步紧循环,例如setTimeout
排队调用也会在事件循环的不同部分运行,而不像Promise.then
调用这样的微任务。虽然这不是示例代码的问题,但如果您希望它们在所有情况下都是等效的,那么它会给您带来问题。。您正在寻找Promise.resolve()。然后(慢速)
类似于setTimeout(慢速,0)
Thank You@Bergi这就是我想要的答案。如果你把它作为一个答案,我会接受的。你是对的,这是一个长期运行的任务,我只是说它模拟了一个更有意义的任务。我认为该代码是异步的,因为在这两种情况下,它实际上都是在Promise或setTimeout中运行代码之前运行对log函数的最后一次调用。但它当然不会并行运行,因为javascript是单线程的。但我并不是想并行运行,我只是想理解为什么Promise和setTimeout的行为不同。
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h2>Promise vs setTimeout</h2>
<div><button id="settimeout-test">setTimeout with slow running function</button></div>
<div><button id="promise-test">Promise and slow running function</button></div>
<div><button id="clear">Clear Results</button></div>
<h5>Results</h5>
<div id="result"></div>
<script>
const slow = function() {
let nu = Date.now();
while (Date.now() - nu < 1000) {}
}
const getSlowPromise = () => new Promise(resolve => {
slow();
resolve();
});
const resultsElement = document.getElementById('result')
const log = (message) => {
resultsElement.innerText += message;
}
const settimeoutButton = document.getElementById('settimeout-test');
settimeoutButton.addEventListener('click', () => {
const now = Date.now();
log(`\nsetTimeout test starts after ${Date.now() - now} ms`);
setTimeout(() => {
slow();
log(`\nSlow function completes after ${Date.now() - now} ms`);
}, 0);
log(`\nEvent listener completes after ${Date.now() - now} ms`);
});
const promiseButton = document.getElementById('promise-test');
promiseButton.addEventListener('click', () => {
const now = Date.now();
log(`\nsetTimeout test starts after ${Date.now() - now} ms`);
getSlowPromise().then(res => log(`\nPromise completes after ${Date.now() - now} ms`));
log(`\nevent listener completes after ${Date.now() - now} ms`);
})
const clear = () => resultsElement.innerText = '';
const clearButton = document.getElementById('clear');
clearButton.addEventListener('click', () => clear());
</script>
</body>
</html>