mirror of https://github.com/linebender/xilem
xilem_web: Optimize element casting, and intern often used strings (e.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.
This commit is contained in:
parent
d758ae508e
commit
2ccd9d4712
|
@ -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"]
|
||||
|
|
|
@ -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(_) => (),
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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() {
|
||||
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
};
|
||||
|
@ -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()
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue