zulip/static/js/recent_topics_util.js

44 lines
1.1 KiB
JavaScript
Raw Normal View History

import $ from "jquery";
import * as compose_state from "./compose_state";
import * as overlays from "./overlays";
import * as popovers from "./popovers";
recent_topics: Don't rely on ":visible" to avoid forced reflow. Previously, navigating from any stream to the recent topics view would cause a forced reflow every time we checked `is_visible()` because it would call `$("#recent_topics_view").is(":visible")`. The reason for this is related to how browsers ship frames, the process follows these steps: JavaScript > style calculations > layout > paint > composite. (The layout step is called Reflow in firefox.) Typically, the browser will handle these steps in the most optimal manner possible, delaying expensive operations until they're needed. However, it is possible to cause the browser to perform a layout earlier than necessary. An example of this is what we previously did: When we call `top_left_corner.narrow_to_recent_topics()`, we ask to add a class via `.addClass()`, this schedules a Style Recalculation, then, when we call `message_view_header.make_message_view_header()` it calls `recent_topics_util.is_visible()` which calls `$("#recent_topics_view").is(":visible")`. Before the browser can get this value, it realizes that our dom was invalidated by `.addClass()` and so it must execute the scheduled Style Recalculation and cause a layout. This is called a forced synchronous layout. This commit adds a JavaScript variable representing the visible state, in order to prevent the above behavior. This commit reduces the main thread run time of `build_message_view_header` from 131.81 ms to 5.20 ms. Unfortunately we still have the case where `recent_topics_ui.revive_current_focus()` calls `recent_topics_ui.set_table_focus()` which causes a reflow. However, by eliminating this reflow we still save ~100ms. (It's important to note that we only save this sometimes, as other things can still cost us a reflow.) Further reading: https://developers.google.com/web/fundamentals/ performance/rendering/avoid-large-complex-layouts-and-layout-thrashing
2021-11-05 21:21:43 +01:00
let is_rt_visible = false;
export function set_visible(value) {
is_rt_visible = value;
}
export function is_visible() {
recent_topics: Don't rely on ":visible" to avoid forced reflow. Previously, navigating from any stream to the recent topics view would cause a forced reflow every time we checked `is_visible()` because it would call `$("#recent_topics_view").is(":visible")`. The reason for this is related to how browsers ship frames, the process follows these steps: JavaScript > style calculations > layout > paint > composite. (The layout step is called Reflow in firefox.) Typically, the browser will handle these steps in the most optimal manner possible, delaying expensive operations until they're needed. However, it is possible to cause the browser to perform a layout earlier than necessary. An example of this is what we previously did: When we call `top_left_corner.narrow_to_recent_topics()`, we ask to add a class via `.addClass()`, this schedules a Style Recalculation, then, when we call `message_view_header.make_message_view_header()` it calls `recent_topics_util.is_visible()` which calls `$("#recent_topics_view").is(":visible")`. Before the browser can get this value, it realizes that our dom was invalidated by `.addClass()` and so it must execute the scheduled Style Recalculation and cause a layout. This is called a forced synchronous layout. This commit adds a JavaScript variable representing the visible state, in order to prevent the above behavior. This commit reduces the main thread run time of `build_message_view_header` from 131.81 ms to 5.20 ms. Unfortunately we still have the case where `recent_topics_ui.revive_current_focus()` calls `recent_topics_ui.set_table_focus()` which causes a reflow. However, by eliminating this reflow we still save ~100ms. (It's important to note that we only save this sometimes, as other things can still cost us a reflow.) Further reading: https://developers.google.com/web/fundamentals/ performance/rendering/avoid-large-complex-layouts-and-layout-thrashing
2021-11-05 21:21:43 +01:00
return is_rt_visible;
}
export function is_in_focus() {
// Check if user is focused on
// recent topics.
return (
is_visible() &&
!compose_state.composing() &&
!popovers.any_active() &&
!overlays.is_overlay_or_modal_open() &&
!$(".home-page-input").is(":focus")
);
}
export function get_topic_key(stream_id, topic) {
return stream_id + ":" + topic.toLowerCase();
}
export function get_key_from_message(msg) {
if (msg.type === "private") {
// The to_user_ids field on a private message object is a
// string containing the user IDs involved in the message in
// sorted order.
return msg.to_user_ids;
} else if (msg.type === "stream") {
return get_topic_key(msg.stream_id, msg.topic);
}
throw new Error(`Invalid message type ${msg.type}`);
}