Files
OxideJS-New/crates/oxide_vm/src/promise/jobs.rs
T

116 lines
3.9 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 微任务队列: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);
}
}
}