Ano*_*nEq 11 javascript asynchronous event-loop promise
The following quotes are my primary references for understanding microtask queue processing:
Microtasks (which promises use) are processed when the JS stack empties.
That doesn't make sense to me.
One go-around of the event loop will have exactly one task being processed from the macrotask queue (this queue is simply called the task queue in the WHATWG specification). After this macrotask has finished, all available microtasks will be processed, namely within the same go-around cycle.
Now, regarding line 9 (**) in the following snippet:
From stepping through this snippet w/ debugger, the execution stack does not appear empty when these .then( callback ) microtasks are processed/executed.
Are regular functions like f2() considered a task (aka macrotask)? (when it returns it's an event loop nextTick() and the microtask queue is processed)
Why are microtasks executing when the JS stack is not empty?
function f2() {
let x = new Promise( (resolve, reject) => { resolve( () => {console.log('howdy')} ) })
return x
}
async function f1(){
let y = Promise.resolve().then(() => { console.log('yo1')})
console.log('yo2')
let r2awaited = await f2() //** 'yo0' and 'yo1' log when the interpreter hits this line.
return r2awaited
}
async function start(){
let y = Promise.resolve().then(() => { console.log('yo0')})
let xx = await f1()
console.log('main call return:')
console.log(xx)
}
start()Run Code Online (Sandbox Code Playgroud)
Edit: Another peculiar finding - when you add xx() right after console.log(xx) on line 17, the stack is completely cleared prior to executing the microtasks.
The call stack 1 step prior to microtask queue processing:
Then the immediate next step.
Between these two steps, the microtask queue was processed.
Does the call stack clear [under the hood] between these steps^?
And then is a new call stack created according to the required lexical environment(s) for code after the await [expression]?
Edit: At the time of posting this, I was not aware that everything below the -----(async)----- line in the chrome debugger's call stack was part of a 'fake stack'.
This 'fake stack' is presented for async debugging in a way consistent with sync debugging.
Only the elements above this -----(async)----- line are part of the real main thread call stack.
“当JS堆栈为空时,将处理微任务(承诺使用)。” -杰克·阿奇博尔德(对我没什么意义)
“调用堆栈”是当前正在执行的事情的列表:
function foo() {
debugger;
console.log('foo');
}
function bar() {
foo();
debugger;
}
bar();
Run Code Online (Sandbox Code Playgroud)
当我们碰到的第一个调试器语句,脚本仍在执行,由于是bar,因为是foo。由于存在父子关系,因此堆栈为script > bar > foo。当我们点击第二个调试器语句时,foo已经完成执行,因此它不再在堆栈中。堆栈是script > bar。
当堆栈变空时,微任务队列将一直处理到空为止。
“事件循环的一次复现将恰好从宏任务队列中处理一个任务(在WHATWG规范中,该队列简称为任务队列)。完成此宏任务后,将处理所有可用的微任务,即在相同的复飞周期。” - 堆栈溢出
编辑:我一直读上面的“宏任务”为“微任务”。浏览器中并没有真正的宏任务队列,它只是一个任务队列。
尽管在处理任务之后确实存在微任务处理点,但实际上只有在处理将任务排队以将微任务排队的规范时才需要处理,而无需先调用JS。在大多数情况下,当JS堆栈清空时,微任务队列就会清空。
通过逐步执行带有调试器的代码片段,当处理/执行这些.then(callback)微任务时,执行堆栈不会显示为空。
执行回调时,堆栈永远不会为空,因为回调本身将位于堆栈上。但是,如果这是堆栈上的唯一内容,则可以假定在调用此回调之前堆栈为空。
Chrome的devtools试图帮助维护“异步”堆栈,但这并不是真正的堆栈。真正的堆栈是第一条“异步”行之前的所有内容。
像f2()这样的常规函数是否被视为一项任务
作为任务或微任务不是功能的属性。可以在任务,微任务和事件循环的其他部分(例如渲染)中调用相同的函数。例如:
function foo() {}
// Here, I'll call foo() as part of the current task:
foo();
// Here, I'll let the browser call foo() in a future task:
setTimeout(foo);
// Here, I'll let the browser call foo() in a microtask:
Promise.resolve().then(foo);
// Here, I'll let the browser call foo() as part of the render steps:
requestAnimationFrame(foo);
Run Code Online (Sandbox Code Playgroud)
在你的榜样,f2是不是一个microtask中调用。有点像这样:
function three() {}
function two() {}
async function one() {
await two();
three();
}
one();
Run Code Online (Sandbox Code Playgroud)
在这里,one()在执行脚本的任务中被调用。同步one()调用two(),因此它作为同一任务的一部分运行。然后我们await调用的结果two()。因为我们await,函数的其余部分在微任务中运行。three()被称为,因此它在相同的微任务中运行。
| 归档时间: |
|
| 查看次数: |
795 次 |
| 最近记录: |