1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 15:24:46 -05:00

refactor(core): Extract JsRuntime::poll_value out of JsRuntime::resolve_value (#13461)

This commit is contained in:
Rafael Ávila de Espíndola 2022-01-24 11:59:41 -05:00 committed by GitHub
parent 23d2b34d4b
commit ae0414fa35
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -686,6 +686,42 @@ impl JsRuntime {
scope.perform_microtask_checkpoint(); scope.perform_microtask_checkpoint();
} }
pub fn poll_value(
&mut self,
global: &v8::Global<v8::Value>,
cx: &mut Context,
) -> Poll<Result<v8::Global<v8::Value>, Error>> {
let state = self.poll_event_loop(cx, false);
let mut scope = self.handle_scope();
let local = v8::Local::<v8::Value>::new(&mut scope, global);
if let Ok(promise) = v8::Local::<v8::Promise>::try_from(local) {
match promise.state() {
v8::PromiseState::Pending => match state {
Poll::Ready(Ok(_)) => {
let msg = "Promise resolution is still pending but the event loop has already resolved.";
Poll::Ready(Err(generic_error(msg)))
}
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
Poll::Pending => Poll::Pending,
},
v8::PromiseState::Fulfilled => {
let value = promise.result(&mut scope);
let value_handle = v8::Global::new(&mut scope, value);
Poll::Ready(Ok(value_handle))
}
v8::PromiseState::Rejected => {
let exception = promise.result(&mut scope);
Poll::Ready(exception_to_err_result(&mut scope, exception, false))
}
}
} else {
let value_handle = v8::Global::new(&mut scope, local);
Poll::Ready(Ok(value_handle))
}
}
/// Waits for the given value to resolve while polling the event loop. /// Waits for the given value to resolve while polling the event loop.
/// ///
/// This future resolves when either the value is resolved or the event loop runs to /// This future resolves when either the value is resolved or the event loop runs to
@ -694,38 +730,7 @@ impl JsRuntime {
&mut self, &mut self,
global: v8::Global<v8::Value>, global: v8::Global<v8::Value>,
) -> Result<v8::Global<v8::Value>, Error> { ) -> Result<v8::Global<v8::Value>, Error> {
poll_fn(|cx| { poll_fn(|cx| self.poll_value(&global, cx)).await
let state = self.poll_event_loop(cx, false);
let mut scope = self.handle_scope();
let local = v8::Local::<v8::Value>::new(&mut scope, &global);
if let Ok(promise) = v8::Local::<v8::Promise>::try_from(local) {
match promise.state() {
v8::PromiseState::Pending => match state {
Poll::Ready(Ok(_)) => {
let msg = "Promise resolution is still pending but the event loop has already resolved.";
Poll::Ready(Err(generic_error(msg)))
},
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
Poll::Pending => Poll::Pending,
},
v8::PromiseState::Fulfilled => {
let value = promise.result(&mut scope);
let value_handle = v8::Global::new(&mut scope, value);
Poll::Ready(Ok(value_handle))
}
v8::PromiseState::Rejected => {
let exception = promise.result(&mut scope);
Poll::Ready(exception_to_err_result(&mut scope, exception, false))
}
}
} else {
let value_handle = v8::Global::new(&mut scope, local);
Poll::Ready(Ok(value_handle))
}
})
.await
} }
/// Runs event loop to completion /// Runs event loop to completion
@ -1859,6 +1864,51 @@ pub mod tests {
} }
} }
#[tokio::test]
async fn test_poll_value() {
run_in_task(|cx| {
let mut runtime = JsRuntime::new(Default::default());
let value_global = runtime
.execute_script("a.js", "Promise.resolve(1 + 2)")
.unwrap();
let v = runtime.poll_value(&value_global, cx);
{
let scope = &mut runtime.handle_scope();
assert!(
matches!(v, Poll::Ready(Ok(v)) if v.open(scope).integer_value(scope).unwrap() == 3)
);
}
let value_global = runtime
.execute_script(
"a.js",
"Promise.resolve(new Promise(resolve => resolve(2 + 2)))",
)
.unwrap();
let v = runtime.poll_value(&value_global, cx);
{
let scope = &mut runtime.handle_scope();
assert!(
matches!(v, Poll::Ready(Ok(v)) if v.open(scope).integer_value(scope).unwrap() == 4)
);
}
let value_global = runtime
.execute_script("a.js", "Promise.reject(new Error('fail'))")
.unwrap();
let v = runtime.poll_value(&value_global, cx);
assert!(
matches!(v, Poll::Ready(Err(e)) if e.downcast_ref::<JsError>().unwrap().message == "Uncaught Error: fail")
);
let value_global = runtime
.execute_script("a.js", "new Promise(resolve => {})")
.unwrap();
let v = runtime.poll_value(&value_global, cx);
matches!(v, Poll::Ready(Err(e)) if e.to_string() == "Promise resolution is still pending but the event loop has already resolved.");
});
}
#[tokio::test] #[tokio::test]
async fn test_resolve_value() { async fn test_resolve_value() {
let mut runtime = JsRuntime::new(Default::default()); let mut runtime = JsRuntime::new(Default::default());