Giter Site home page Giter Site logo

Comments (8)

krausest avatar krausest commented on July 18, 2024 1

Please create a PR and I‘ll take a look at it.

from js-framework-benchmark.

syduki avatar syduki commented on July 18, 2024

Faster than vanillajs can be only vanillajs.
Jokes aside, there is an issue in this very case as well as in general, it is related not with measurements but with the simplicity of this very benchmark. So, here is either an over-optimization or a deviation from the expected implementation (aka cheating) in your toy framework which tricks the benchmark.
With that being said, those figures are easily achieved with a simple css rule, like this one:

table tr:nth-child(n+11) { display: none; }

@krausest I guess this "issue" is a evidence that some kind of checking for elements visibility should be implemented to improve the reliability of the benchmark.

from js-framework-benchmark.

Niedzwiedzw avatar Niedzwiedzw commented on July 18, 2024

Faster than vanillajs can be only vanillajs. Jokes aside, there is an issue in this very case as well as in general, it is related not with measurements but with the simplicity of this very benchmark. So, here is either an over-optimization or a deviation from the expected implementation (aka cheating) in your toy framework which tricks the benchmark. With that being said, those figures are easily achieved with a simple css rule, like this one:

table tr:nth-child(n+11) { display: none; }

@krausest I guess this "issue" is a evidence that some kind of checking for elements visibility should be implemented to improve the reliability of the benchmark.

Thank you for replying. I am happy to collaborate in order to track down the exact cause. My implementation is pretty much a mix of an immediate mode gui with elm-like message passing. I'm hooking the dom events with messages that then get handled asynchronously (updating the app state), and then running old_builder.rebuild(new_builder) - comparing old changes with the new changes and applying the diff. Framework was not written with cheating of any benchmark in mind. To be honest, I haven't done any optimizations at this point as I focused on the api and only ran the benchmark out of curiosity.

TLDR: I'm not a troll :P

from js-framework-benchmark.

Niedzwiedzw avatar Niedzwiedzw commented on July 18, 2024
use std::sync::atomic::{AtomicUsize, Ordering};

use futures_util::StreamExt;
use korvin::core::{
    element_builder::{AsElementBuilder, ElementBuilder},
    flavors::elm_like::Communicator,
    Runtime,
};
use rand::{seq::SliceRandom, thread_rng};
use web_sys::MouseEvent;

static ADJECTIVES: &[&str] = &[
    "pretty",
    "large",
    "big",
    "small",
    "tall",
    "short",
    "long",
    "handsome",
    "plain",
    "quaint",
    "clean",
    "elegant",
    "easy",
    "angry",
    "crazy",
    "helpful",
    "mushy",
    "odd",
    "unsightly",
    "adorable",
    "important",
    "inexpensive",
    "cheap",
    "expensive",
    "fancy",
];

static COLOURS: &[&str] = &[
    "red", "yellow", "blue", "green", "pink", "brown", "purple", "brown", "white", "black",
    "orange",
];

static NOUNS: &[&str] = &[
    "table", "chair", "house", "bbq", "desk", "car", "pony", "cookie", "sandwich", "burger",
    "pizza", "mouse", "keyboard",
];

fn button<F: FnOnce(ElementBuilder) -> ElementBuilder>(
    id: &str,
    text: &str,
    button: F,
) -> ElementBuilder {
    "div".attribute("class", "col-sm-6 smallpad").child(button(
        "button"
            .attribute("id", id)
            .attribute("class", "btn btn-primary btn-block")
            .attribute("type", "button")
            .text(text),
    ))
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct RowData {
    id: usize,
    label: String,
}

static ID_COUNTER: AtomicUsize = AtomicUsize::new(1);

fn build_data(count: usize) -> Vec<RowData> {
    let mut thread_rng = thread_rng();

    let mut data = Vec::new();
    data.reserve_exact(count);

    for _i in 0..count {
        let adjective = ADJECTIVES.choose(&mut thread_rng).unwrap();
        let colour = COLOURS.choose(&mut thread_rng).unwrap();
        let noun = NOUNS.choose(&mut thread_rng).unwrap();
        let capacity = adjective.len() + colour.len() + noun.len() + 2;
        let mut label = String::with_capacity(capacity);
        label.push_str(adjective);
        label.push(' ');
        label.push_str(colour);
        label.push(' ');
        label.push_str(noun);

        data.push(RowData {
            id: ID_COUNTER.fetch_add(1, Ordering::Relaxed),
            label,
        });
    }

    data
}

#[derive(Default)]
struct App {
    data: Vec<RowData>,
    selected: Option<usize>,
}

impl App {
    fn handle(&mut self, message: AppMessage) {
        match message {
            AppMessage::Create1000Rows => self.data = build_data(1000),
            AppMessage::Create10000Rows => self.data = build_data(10000),
            AppMessage::Append1000Rows => self.data.append(&mut build_data(1000)),
            AppMessage::UpdateEvery10thRow => self
                .data
                .iter_mut()
                .step_by(10)
                .for_each(|row| row.label.push_str(" !!!")),
            AppMessage::Clear => {
                self.selected = None;
                self.data.clear();
            }
            AppMessage::SwapRows => {
                if self.data.len() > 998 {
                    self.data.swap(1, 998)
                }
            }
            AppMessage::SetSelected(id) => self.selected = Some(id),
            AppMessage::Remove(id) => self.data.retain(|row| row.id != id),
        }
    }
}

#[derive(Clone, Copy, Hash)]
enum AppMessage {
    Create1000Rows,
    Create10000Rows,
    Append1000Rows,
    UpdateEvery10thRow,
    Clear,
    SwapRows,
    SetSelected(usize),
    Remove(usize),
}

fn app(communicator: Communicator<AppMessage>, App { data, selected }: &App) -> ElementBuilder {
    let div = |class: &str| "div".attribute("class", class);
    let mousedown_send = move |message| move |_: MouseEvent| communicator.send(message);
    let element_mousedown_send = |element: ElementBuilder, message| {
        element.event(message, "mousedown", mousedown_send(message))
    };

    let message_button =
        |id, text, message| button(id, text, |button| element_mousedown_send(button, message));
    let jumbotron = div("jumbotron")
        .child(div("col-md-6").child("h1".text("Korvin")))
        .child(div("col-md-6"))
        .child(
            div("row")
                .child(message_button(
                    "run",
                    "Create 1,000 rows",
                    AppMessage::Create1000Rows,
                ))
                .child(message_button(
                    "runlots",
                    "Create 10,000 rows",
                    AppMessage::Create10000Rows,
                ))
                .child(message_button(
                    "add",
                    "Append 1,000 rows",
                    AppMessage::Append1000Rows,
                ))
                .child(message_button(
                    "update",
                    "Update every 10th row",
                    AppMessage::UpdateEvery10thRow,
                ))
                .child(message_button("clear", "Clear", AppMessage::Clear))
                .child(message_button(
                    "swaprows",
                    "Swap Rows",
                    AppMessage::SwapRows,
                )),
        );
    let table = "table"
        .attribute("class", "table table-hover table-striped test-data")
        .child("tbody".children(data.iter().map(|RowData { id, label }| {
            let mut tr = "tr".into_builder();
            if selected
                .as_ref()
                .map(|selected| selected.eq(id))
                .unwrap_or_default()
            {
                tr = tr.attribute("class", "danger");
            }
            let td = |class: &str| "td".attribute("class", class);
            let row = {
                td("col-md-4").child(element_mousedown_send(
                    "a".text(label.as_str()),
                    AppMessage::SetSelected(*id),
                ))
            };
            tr.child(td("col-md-1").text(id.to_string().as_str()))
                .child(row)
                .child(
                    td("col-md-1").child(element_mousedown_send(
                        "a".child(
                            "span"
                                .attribute("class", "glyphicon glyphicon-remove")
                                .attribute("aria-hidden", "true"),
                        ),
                        AppMessage::Remove(*id),
                    )),
                )
                .child(td("col-md-6"))
        })));
    div("container").child(jumbotron).child(table).child(
        "span"
            .attribute("class", "preloadicon glyphicon glyphicon-remove")
            .attribute("aria-hidden", "true"),
    )
}

fn main() {
    console_error_panic_hook::set_once();
    let main = web_sys::window()
        .and_then(|w| w.document())
        .map(|d| d.query_selector("#main").unwrap().unwrap())
        .unwrap();

    wasm_bindgen_futures::spawn_local(async move {
        let mut runtime = Runtime::new(main);
        let (mut rx, communicator) = Communicator::create();
        let mut state = App::default();

        runtime
            .dom_executor
            .rebuild(app(communicator, &state).build())
            .unwrap();
        while let Some(message) = rx.next().await {
            state.handle(message);
            runtime
                .dom_executor
                .rebuild(app(communicator, &state).build())
                .unwrap()
        }
    });
}

here is the code for reference

from js-framework-benchmark.

syduki avatar syduki commented on July 18, 2024

TLDR: I'm not a troll :P

Don't get me wrong, people love challenges and some frameworks in this benchmark can be tracked down to have been built just to fulfill the purpose of "fastest framework".
Anyway, I see this is a Rust implementation and the few Rust frameworks here doesn't show such a breakthrough in performance. Again, as I said, I personally don't think this is a measurement issue, as the measurements here are pretty straightforward and have been battle-tested on very different kind of implementations. Thus my only assumption is that there is something wrong within your framework/implementation, but I cannot confirm this only by looking at the code you provided. Maybe you can just submit a PR with this non-keyed framework, for a better visibility for all concerned?

from js-framework-benchmark.

Niedzwiedzw avatar Niedzwiedzw commented on July 18, 2024

@krausest #1451

sorry for the delay, but as I said it's a toy project and I needed to clean it up, also korvin is a much more serious name than bimber (kind of polish alcoholic drink). In case you need help with building everything from source ping me on discord: niedzwiedzw

from js-framework-benchmark.

Niedzwiedzw avatar Niedzwiedzw commented on July 18, 2024

repo with library source code:
https://github.com/Niedzwiedzw/korvin

from js-framework-benchmark.

Niedzwiedzw avatar Niedzwiedzw commented on July 18, 2024

we have figured out the reason of measurement corruption
turns out the implementation needs to use "click" event, as using "mousedown" will offset the measurement by the browser lag. closing :)
image

from js-framework-benchmark.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.