浏览代码

list: do not use IntersectionObserver to reduce CPU usage

Switch back to a custom spinner detection, as the IntersectionObserver
is eating a lot of CPU resources on idle.

This should also take care of #2250 properly: the previous `onDestroyed()`
was removing the resize and scroll callbacks, but they were not unique
enough, and they were shared across swimlanes. So if a list had 2 swimlanes
with spinners, when one was removed, the other was not triggering its
callbacks anymore.

Related: #2294
Benjamin Tissoires 6 年之前
父节点
当前提交
261754f18b
共有 1 个文件被更改,包括 30 次插入20 次删除
  1. 30 20
      client/components/lists/listBody.js

+ 30 - 20
client/components/lists/listBody.js

@@ -615,40 +615,50 @@ BlazeComponent.extendComponent({
 
 BlazeComponent.extendComponent({
   onCreated() {
-    this.spinnerShown = false;
     this.cardlimit = this.parentComponent().cardlimit;
+
+    this.listId = this.parentComponent().data()._id;
+    this.swimlaneId = '';
+
+    const boardView = Meteor.user().profile.boardView;
+    if (boardView === 'board-view-swimlanes')
+      this.swimlaneId = this.parentComponent().parentComponent().parentComponent().data()._id;
   },
 
   onRendered() {
-    const spinner = this.find('.sk-spinner-list');
-
-    if (spinner) {
-      const options = {
-        root: null, // we check if the spinner is on the current viewport
-        rootMargin: '0px',
-        threshold: 0.25,
-      };
-
-      this.observer = new IntersectionObserver((entries) => {
-        entries.forEach((entry) => {
-          this.spinnerShown = entry.isIntersecting;
-          this.updateList();
-        });
-      }, options);
+    this.spinner = this.find('.sk-spinner-list');
+    this.container = this.$(this.spinner).parents('.js-perfect-scrollbar')[0];
 
-      this.observer.observe(spinner);
-    }
+    $(this.container).on(`scroll.spinner_${this.swimlaneId}_${this.listId}`, () => this.updateList());
+    $(window).on(`resize.spinner_${this.swimlaneId}_${this.listId}`, () => this.updateList());
+
+    this.updateList();
   },
 
   onDestroyed() {
-    this.observer.disconnect();
+    $(this.container).off(`scroll.spinner_${this.swimlaneId}_${this.listId}`);
+    $(window).off(`resize.spinner_${this.swimlaneId}_${this.listId}`);
   },
 
   updateList() {
-    if (this.spinnerShown) {
+    if (this.spinnerInView()) {
       this.cardlimit.set(this.cardlimit.get() + InfiniteScrollIter);
       window.requestIdleCallback(() => this.updateList());
     }
   },
 
+  spinnerInView() {
+    const parentViewHeight = this.container.clientHeight;
+    const bottomViewPosition = this.container.scrollTop + parentViewHeight;
+
+    const threshold = this.spinner.offsetTop;
+
+    // spinner deleted
+    if (!this.spinner.offsetTop) {
+      return false;
+    }
+
+    return bottomViewPosition > threshold;
+  },
+
 }).register('spinnerList');