add more internal documentation about tasks

This commit is contained in:
Evan Almloff 2024-03-04 15:38:28 -06:00
parent 48f845985b
commit b42992bad1
3 changed files with 39 additions and 1 deletions

View file

@ -1,3 +1,32 @@
//! Dioxus resolves scopes in a specific order to avoid unexpected behavior. All tasks are resolved in the order of height. Scopes that are higher up in the tree are resolved first.
//! When a scope that is higher up in the tree is rerendered, it may drop scopes lower in the tree along with their tasks.
//!
//! ```rust
//! use dioxus::prelude::*;
//!
//! fn app() -> Element {
//! let vec = use_signal(|| vec![0; 10]);
//! rsx! {
//! // If the length of the vec shrinks we need to make sure that the children are dropped along with their tasks the new state of the vec is read
//! for idx in 0..vec.len() {
//! Child { idx, vec }
//! }
//! }
//! }
//!
//! #[component]
//! fn Child(vec: Signal<Vec<usize>>, idx: usize) -> Element {
//! use_hook(|| {
//! spawn(async {
//! // If we let this task run after the child is dropped, it will panic.
//! println!("Task {}", vec.read()[idx]);
//! });
//! });
//!
//! rsx! {}
//! }
//! ```
use crate::ScopeId;
use crate::Task;
use std::borrow::Borrow;
@ -49,6 +78,7 @@ pub struct DirtyScopes {
}
impl DirtyScopes {
/// Queue a task to be polled
pub fn queue_task(&mut self, task: Task, order: ScopeOrder) {
match self.tasks.get(&order) {
Some(scope) => scope.queue_task(task),
@ -60,22 +90,27 @@ impl DirtyScopes {
}
}
/// Queue a scope to be rerendered
pub fn queue_scope(&mut self, order: ScopeOrder) {
self.scopes.insert(order);
}
/// Check if there are any dirty scopes
pub fn has_dirty_scopes(&self) -> bool {
!self.scopes.is_empty()
}
/// Take any tasks from the highest scope
pub fn pop_task(&mut self) -> Option<DirtyTasks> {
self.tasks.pop_first()
}
/// Take the highest scope that needs to be rerendered
pub fn pop_scope(&mut self) -> Option<ScopeOrder> {
self.scopes.pop_first()
}
/// Take any work from the highest scope. This may include rerunning the scope and/or running tasks
pub fn pop_work(&mut self) -> Option<Work> {
let dirty_scope = self.scopes.first();
let dirty_task = self.tasks.first();

View file

@ -1,3 +1,5 @@
//! In dioxus, effects are run using normal async functions after a render. [RenderSignalFuture] is a future that resolves after a render has passed.
use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;

View file

@ -439,7 +439,7 @@ impl VirtualDom {
self.poll_tasks().await;
}
///
/// Poll the scheduler for any work
async fn poll_tasks(&mut self) {
loop {
// Process all events - Scopes are marked dirty, etc
@ -454,6 +454,7 @@ impl VirtualDom {
// Make sure we set the runtime since we're running user code
let _runtime = RuntimeGuard::new(self.runtime.clone());
/// There isn't any more work we can do synchronously. Wait for any new work to be ready
match self.rx.next().await.expect("channel should never close") {
SchedulerMsg::Immediate(id) => self.mark_dirty(id),
SchedulerMsg::TaskNotified(id) => {