[oden-js] Promise completion needs to be more robust
As predicted.
This commit is contained in:
parent
44c39b1740
commit
b77e7eba3e
1 changed files with 33 additions and 26 deletions
|
|
@ -175,37 +175,44 @@ impl Runtime {
|
||||||
|
|
||||||
/// Process all pending async jobs. This includes all promise resolutions.
|
/// Process all pending async jobs. This includes all promise resolutions.
|
||||||
fn process_promise_completions(&self) {
|
fn process_promise_completions(&self) {
|
||||||
// TODO: This could be more robust if we buffered all the completed
|
let mut promises = vec![];
|
||||||
// promise entries and then dropped the borrow of the state, so
|
|
||||||
// that we never invoked user code while borrowing our private
|
// First, gather all the completed promises into a temporary vector
|
||||||
// state mutably.
|
// so that we only need to borrow our mutable state for a short
|
||||||
|
// period of time.
|
||||||
let mut state = unsafe { PrivateState::from_rt_mut(self.rt) };
|
let mut state = unsafe { PrivateState::from_rt_mut(self.rt) };
|
||||||
while let Ok((handle, evt)) = state.promise_recv.try_recv() {
|
while let Ok((handle, evt)) = state.promise_recv.try_recv() {
|
||||||
if let Some(entry) = state.promise_table.remove(&handle) {
|
if let Some(entry) = state.promise_table.remove(&handle) {
|
||||||
let ctx = ContextRef::from_raw(entry.context);
|
promises.push((entry, evt));
|
||||||
let (callback, value) = match evt {
|
|
||||||
PromiseEvent::Resolved(v) => (entry.resolve, v),
|
|
||||||
PromiseEvent::Rejected(v) => (entry.reject, v),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Convert the result into a JS value, which we can only
|
|
||||||
// really do while we are on this thread.
|
|
||||||
let value = value(&ctx).expect("Should be able to convert promise result to value");
|
|
||||||
|
|
||||||
// Call the particular callback and make sure it doesn't throw.
|
|
||||||
ctx.check_exception(unsafe {
|
|
||||||
let mut args = [value.val];
|
|
||||||
sys::JS_Call(
|
|
||||||
entry.context,
|
|
||||||
callback,
|
|
||||||
sys::JS_MakeUndefined(),
|
|
||||||
1,
|
|
||||||
args.as_mut_ptr(),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.expect("Exception thrown by promise callback");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
drop(state); // Don't need our internal state anymore.
|
||||||
|
|
||||||
|
// Nowe we can complete all the promises.
|
||||||
|
for (entry, evt) in promises {
|
||||||
|
let ctx = ContextRef::from_raw(entry.context);
|
||||||
|
let (callback, value) = match evt {
|
||||||
|
PromiseEvent::Resolved(v) => (entry.resolve, v),
|
||||||
|
PromiseEvent::Rejected(v) => (entry.reject, v),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert the result into a JS value, which we can only
|
||||||
|
// really do while we are on this thread.
|
||||||
|
let value = value(&ctx).expect("Should be able to convert promise result to value");
|
||||||
|
|
||||||
|
// Call the particular callback and make sure it doesn't throw.
|
||||||
|
ctx.check_exception(unsafe {
|
||||||
|
let mut args = [value.val];
|
||||||
|
sys::JS_Call(
|
||||||
|
entry.context,
|
||||||
|
callback,
|
||||||
|
sys::JS_MakeUndefined(),
|
||||||
|
1,
|
||||||
|
args.as_mut_ptr(),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.expect("Exception thrown by promise callback");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process all pending async jobs. This includes all promise resolutions.
|
/// Process all pending async jobs. This includes all promise resolutions.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue