[英]Unclear behavior of JavaScript fetch() resolution
我试图理解 fetch() 的执行流程,但这与我的实验不一致。
我找到了这个答案https://stackoverflow.com/a/62566665/15933760
fetch 方法确实会立即启动一个网络请求,该请求将被“并行”处理,即在事件循环之外。 当接收到请求响应(不是它的主体,通常是标头)时,浏览器将排队一个新任务,该任务仅负责解析 Promise,从而将其微任务排队。
我理解它,除了任务/微任务排队位。 这是我尝试进行的实验:
function delay() {
i=0;
while(i<1000000000) i++;
}
console.log('start');
setTimeout(()=> {
console.log('start macrotask');
delay();
console.log('end macrotask');
}, 0);
Promise.resolve().then(() => {
console.log('start promise handler');
delay();
console.log('end promise handler');
});
console.log('calling fetch');
fetch('http://127.0.0.1:9999/').then(function(result) {
console.log('success start fetch handler');
delay();
console.log('success end fetch handler');
},
function(error) {
console.log('error start fetch handler');
delay();
console.log('error end fetch handler');
});
console.log('done calling fetch');
delay();
delay();
delay();
delay();
delay();
delay();
delay();
delay();
delay();
delay();
delay();
delay();
delay();
Promise.resolve().then(() => {
console.log('start 2nd promise handler');
delay();
console.log('end 2nd promise handler');
});
setTimeout(()=> {
console.log('start 2nd macrotask');
delay();
console.log('end 2nd macrotask');
}, 0);
delay();
console.log('end');
在我的 Chrome 控制台中,这会输出:
start
calling fetch
done calling fetch
end
start promise handler
end promise handler
start 2nd promise handler
end 2nd promise handler
undefined
success start fetch handler
success end fetch handler
start macrotask
end macrotask
start 2nd macrotask
end 2nd macrotask
查看我的本地流量,当它输出calling fetch
时,会向 127.0.0.1:9999 发出连接和请求。 此外,如果我将套接字编程为不立即响应,则执行将继续,并且我会立即看到done calling fetch
。
到目前为止,这一切都是一致的,并表明 fetch 与主线程并行执行。
start
calling fetch
done calling fetch
因为 fetch() 继续并行执行,即使在那之后delay()
调用这让我们的队列看起来像这样:
microtask queue: first promise handler
fetch handler
last promise handler
macrotask queue: first timeout callback
last timeout callback
这不一致,因为我们从 output 看到的顺序是:
first promise handler
last promise handler
fetch handler
first timeout callback
last timeout callback
这让我们的队列看起来像这样:
microtask queue: first promise handler
last promise handler
macrotask queue: first timeout callback
fetch task
last timeout callback
这再次不一致,因为我们从 output 看到的顺序是:
first promise handler
last promise handler
fetch handler
first timeout callback
last timeout callback
为了保持一致,它应该在第一个超时回调任务之后执行 promise-resolving 任务。
你说得对, Promises 创建微任务并setTimeout
和fetch
创建任务(宏任务); 我认为这里的问题是延迟0
的setTimeout
不一定会立即排队或与fetch
在同一个任务队列中。
setTimeout
页面列出了延迟超时的几个原因,包括“如果页面(或操作系统/浏览器)忙于其他任务”。setTimeout
定义第 8.6 节链接)允许实现定义的额外延迟(第 5.3 点),该延迟可以降低定时器分辨率以节省功耗和其他原因。
setTimeout
使用“计时器任务源”,而fetch
使用“网络任务源”,因此这些队列中的顺序得到保证,但它们之间的顺序不是:
因此,Chrome 做到了这一点。 对我来说“新闻”的一点是微任务在回调之后处理(只要没有其他 JavaScript 正在执行中),我认为它仅限于任务结束。 此规则来自用于调用回调的 HTML 规范:
[引用]
…并且微任务检查点涉及通过微任务队列,除非我们已经在处理微任务队列。
只要延迟为 0 毫秒的setTimeout
可能不会立即将任务排入与fetch
相同的任务队列,那么行为是自洽的,即使在实践中它可能因浏览器而异。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.