mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-27 04:01:11 +08:00
116 lines
3.9 KiB
Rust
116 lines
3.9 KiB
Rust
//! 微任务队列:FIFO drain 执行与 session GC 的队列值遍历 / 改写。
|
||
|
||
use oxide_types::value::JsValue;
|
||
|
||
use crate::vm::RootGroup;
|
||
use crate::vm::Vm;
|
||
use crate::vm_warn;
|
||
|
||
use super::{Microtask, MAX_DRAIN_JOBS};
|
||
|
||
impl Vm {
|
||
/// drain 微任务队列:FIFO 逐条处理直到清空或达到上限。
|
||
///
|
||
/// 调用时机:`run()` 末尾与事件循环每个 turn 边界。
|
||
///
|
||
/// # 副作用
|
||
/// - 任务内调用 JS 回调(`call_function_sync`),可能入队新任务。
|
||
/// - 单任务抛错不中断 drain(未处理拒绝按规范不可见)。
|
||
pub fn drain_microtasks(&mut self) {
|
||
let mut count = 0usize;
|
||
while let Some(job) = self.job_queue.pop_front() {
|
||
count += 1;
|
||
if count > MAX_DRAIN_JOBS {
|
||
vm_warn!("drain_microtasks: exceeded {MAX_DRAIN_JOBS} microtasks, aborting");
|
||
break;
|
||
}
|
||
self.run_microtask(job);
|
||
}
|
||
}
|
||
|
||
/// 执行单条微任务。
|
||
fn run_microtask(&mut self, job: Microtask) {
|
||
match job {
|
||
Microtask::Reaction {
|
||
is_fulfill,
|
||
handler,
|
||
argument,
|
||
resolve,
|
||
reject,
|
||
} => {
|
||
// 空处理器(undefined/非可调用)→ 值直通:fulfill 调 resolve,reject 调 reject。
|
||
let handler_result = if oxide_builtins::iterator::is_callable(handler) {
|
||
self.call_function_sync(handler, JsValue::undefined(), &[argument])
|
||
} else if is_fulfill {
|
||
Ok(argument)
|
||
} else {
|
||
let _ = self.call_function_sync(reject, JsValue::undefined(), &[argument]);
|
||
return;
|
||
};
|
||
match handler_result {
|
||
Ok(x) => {
|
||
let _ = self.call_function_sync(resolve, JsValue::undefined(), &[x]);
|
||
}
|
||
Err(e) => {
|
||
let exc = self
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e));
|
||
let _ = self.call_function_sync(reject, JsValue::undefined(), &[exc]);
|
||
}
|
||
}
|
||
}
|
||
Microtask::Thenable {
|
||
thenable,
|
||
then,
|
||
resolve,
|
||
reject,
|
||
} => {
|
||
// 委托调用;抛错则拒绝目标 promise。
|
||
match self.call_function_sync(then, thenable, &[resolve, reject]) {
|
||
Ok(_) => {}
|
||
Err(e) => {
|
||
let exc = self
|
||
.last_uncaught_value
|
||
.take()
|
||
.unwrap_or_else(|| oxide_builtins::error::create_from_text(self, &e));
|
||
let _ = self.call_function_sync(reject, JsValue::undefined(), &[exc]);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/// 供外部遍历微任务队列(GC mark/rewrite 用)。
|
||
///
|
||
/// `group` 是调用方传入的根组来源(微任务队列属 `JobQueue` 组),原样透传给
|
||
/// 内层闭包。
|
||
pub(crate) fn for_each_job_value(job: &Microtask, group: RootGroup, mut f: impl FnMut(RootGroup, JsValue)) {
|
||
match job {
|
||
Microtask::Reaction {
|
||
handler,
|
||
argument,
|
||
resolve,
|
||
reject,
|
||
..
|
||
} => {
|
||
f(group, *handler);
|
||
f(group, *argument);
|
||
f(group, *resolve);
|
||
f(group, *reject);
|
||
}
|
||
Microtask::Thenable {
|
||
thenable,
|
||
then,
|
||
resolve,
|
||
reject,
|
||
} => {
|
||
f(group, *thenable);
|
||
f(group, *then);
|
||
f(group, *resolve);
|
||
f(group, *reject);
|
||
}
|
||
}
|
||
}
|