Skip to content

Commit

Permalink
xilem_web: Optimize element casting, and intern often used strings (e…
Browse files Browse the repository at this point in the history
….g. "div") (#594)

Some micro-optimizations, e.g. avoids a js call `instanceof` (via
`dyn_into`/`dyn_ref`) when constructing elements.

Leads to a small speed increase when constructing/visiting elements
(roughly 2%) and more importantly a leaner wasm binary (around 5 %),
respectively tested with the js-framework-benchmark suite.
  • Loading branch information
Philipp-M authored Sep 17, 2024
1 parent d758ae5 commit 2ccd9d4
Show file tree
Hide file tree
Showing 10 changed files with 19 additions and 20 deletions.
2 changes: 2 additions & 0 deletions xilem_web/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,5 @@ features = [
[features]
default = ["hydration"]
hydration = []
# This interns some often used strings, such as element tags ("div" etc.), which slightly improves performance when creating elements at the cost of a bigger wasm binary
intern_strings = ["wasm-bindgen/enable-interning"]
8 changes: 2 additions & 6 deletions xilem_web/src/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,17 +127,13 @@ impl Attributes {
for modifier in self.attribute_modifiers.iter().rev() {
match modifier {
AttributeModifier::Remove(name) => {
if self.updated_attributes.contains_key(name) {
self.updated_attributes.remove(name);
if self.updated_attributes.remove(name).is_some() {
remove_attribute(element, name);
// element.remove_attribute(name);
}
}
AttributeModifier::Set(name, value) => {
if self.updated_attributes.contains_key(name) {
self.updated_attributes.remove(name);
if self.updated_attributes.remove(name).is_some() {
set_attribute(element, name, &value.serialize());
// element.set_attribute(name, &value.serialize());
}
}
AttributeModifier::EndMarker(_) => (),
Expand Down
2 changes: 1 addition & 1 deletion xilem_web/src/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ impl Classes {
// Svg elements do have issues with className, see https://developer.mozilla.org/en-US/docs/Web/API/Element/className
if element.dyn_ref::<web_sys::SvgElement>().is_some() {
element
.set_attribute("class", &self.class_name)
.set_attribute(wasm_bindgen::intern("class"), &self.class_name)
.unwrap_throw();
} else {
element.set_class_name(&self.class_name);
Expand Down
7 changes: 5 additions & 2 deletions xilem_web/src/element_props.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ impl Pod<web_sys::Element, ElementProps> {
/// Creates a new Pod with [`web_sys::Element`] as element and `ElementProps` as its [`DomView::Props`](`crate::DomView::Props`)
pub fn new_element(children: Vec<AnyPod>, ns: &str, elem_name: &str) -> Self {
let element = document()
.create_element_ns(Some(ns), elem_name)
.create_element_ns(
Some(wasm_bindgen::intern(ns)),
wasm_bindgen::intern(elem_name),
)
.unwrap_throw();

for child in children.iter() {
Expand All @@ -93,7 +96,7 @@ impl Pod<web_sys::Element, ElementProps> {
#[cfg(feature = "hydration")]
pub fn hydrate_element(children: Vec<AnyPod>, element: web_sys::Node) -> Self {
Self {
node: element.dyn_into().unwrap_throw(),
node: element.unchecked_into(),
props: ElementProps {
in_hydration: true,
attributes: None,
Expand Down
2 changes: 1 addition & 1 deletion xilem_web/src/elements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ where
.replace_child(&new_element, element.node)
.unwrap_throw();
}
*element.node = new_element.dyn_into().unwrap_throw();
*element.node = new_element.unchecked_into();
}

rebuild_element(
Expand Down
4 changes: 2 additions & 2 deletions xilem_web/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ fn create_event_listener<Event: JsCast + crate::Message>(
) -> Closure<dyn FnMut(web_sys::Event)> {
let thunk = ctx.message_thunk();
let callback = Closure::new(move |event: web_sys::Event| {
let event = event.dyn_into::<Event>().unwrap_throw();
let event = event.unchecked_into::<Event>();
thunk.push_message(event);
});

Expand Down Expand Up @@ -545,7 +545,7 @@ where
ctx.with_id(ON_EVENT_VIEW_ID, |ctx| {
let thunk = ctx.message_thunk();
let callback = Closure::new(move |entries: js_sys::Array| {
let entry: web_sys::ResizeObserverEntry = entries.at(0).dyn_into().unwrap_throw();
let entry: web_sys::ResizeObserverEntry = entries.at(0).unchecked_into();
thunk.push_message(entry);
});

Expand Down
2 changes: 1 addition & 1 deletion xilem_web/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ macro_rules! impl_dom_node_for_elements {
impl From<Pod<web_sys::Element, ElementProps>> for Pod<web_sys::$ty, ElementProps> {
fn from(value: Pod<web_sys::Element, ElementProps>) -> Self {
Self {
node: value.node.dyn_into().unwrap_throw(),
node: value.node.unchecked_into(),
props: value.props,
}
}
Expand Down
2 changes: 1 addition & 1 deletion xilem_web/src/pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ where
ctx.with_id(ViewId::new(0), |ctx| {
let (element, child_state) = self.child.build(ctx);
let thunk = ctx.message_thunk();
let el = element.as_ref().dyn_ref::<web_sys::Element>().unwrap();
let el = element.as_ref().unchecked_ref::<web_sys::Element>();
let el_clone = el.clone();
let down_closure = Closure::new(move |e: PointerEvent| {
thunk.push_message(PointerMsg::Down(PointerDetails::from_pointer_event(&e)));
Expand Down
6 changes: 2 additions & 4 deletions xilem_web/src/style.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,12 @@ impl Styles {
for modifier in self.style_modifiers.iter().rev() {
match modifier {
StyleModifier::Remove(name) => {
if self.updated_styles.contains_key(name) {
self.updated_styles.remove(name);
if self.updated_styles.remove(name).is_some() {
remove_style(element, name);
}
}
StyleModifier::Set(name, value) => {
if self.updated_styles.contains_key(name) {
self.updated_styles.remove(name);
if self.updated_styles.remove(name).is_some() {
set_style(element, name, value);
}
}
Expand Down
4 changes: 2 additions & 2 deletions xilem_web/src/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ macro_rules! impl_string_view {
) -> (Self::OrphanElement, Self::OrphanViewState) {
#[cfg(feature = "hydration")]
let node = if ctx.is_hydrating() {
ctx.hydrate_node().unwrap().dyn_into().unwrap()
ctx.hydrate_node().unwrap().unchecked_into()
} else {
web_sys::Text::new_with_data(view).unwrap()
};
Expand Down Expand Up @@ -81,7 +81,7 @@ macro_rules! impl_to_string_view {
) -> (Self::OrphanElement, Self::OrphanViewState) {
#[cfg(feature = "hydration")]
let node = if ctx.is_hydrating() {
ctx.hydrate_node().unwrap().dyn_into().unwrap()
ctx.hydrate_node().unwrap().unchecked_into()
} else {
web_sys::Text::new_with_data(&view.to_string()).unwrap()
};
Expand Down

0 comments on commit 2ccd9d4

Please sign in to comment.