Troika: Предупреждение «Большое количество открытых запросов WorkerModule, некоторые из них могут не возвращаться»

Созданный на 30 мар. 2021  ·  14Комментарии  ·  Источник: protectwise/troika

Здравствуйте, я вижу большое количество предупреждений, исходящих от troika-worker.utils.esm.js с этим сообщением.

Screen Shot 2021-03-29 at 8 19 42 PM

Хотя вроде все работает нормально

Есть идеи?

Все 14 Комментарий

Хм, это предупреждение не срабатывает, пока не будет > 1000 открытых рабочих запросов. У вас очень большое количество текстовых экземпляров?

Да, но не более 1000 (по крайней мере, не намеренно)

скорее пару сотен

Вот что я визуализирую

Screen Shot 2021-03-30 at 11 03 39 AM

Но так что вы говорите, что, возможно, на моей стороне есть ошибка, из-за которой я создаю больше экземпляров, чем мне на самом деле нужно, и как только я пересекаю счет в 1000, он начинает выдавать ошибку?

Я устанавливал экземпляры, у которых нет содержимого, на .visible = false

но я предполагаю, что это все еще означает, что экземпляр существует

Вы бы порекомендовали вместо использования .visible prop полностью удалить неиспользуемые экземпляры?

Ах, это могло бы объяснить это. Любые вызовы .sync() все равно будут отправлены рабочему процессу в фоновом режиме, даже если visible:false , и они будут накапливаться.

Я думаю, что лично я бы предпочел создавать/удалять метки по запросу или, по крайней мере, предотвращать вызовы .sync() для скрытых. Все эти рабочие запросы используют одного и того же рабочего, поэтому, если он занят обработкой скрытых меток, это может задержать обработку ваших видимых.

Однако я делаю некоторые предположения, не видя вашего точного кода LabelView. Все еще возможно, что на моем конце есть ошибка, так что LMK, что вы найдете.

Просто пытался вызывать .sync() только тогда, когда .visible === true

но все еще получаю предупреждения

если вместо этого я создаю экземпляры только для видимых объектов и уничтожаю неиспользуемые, предупреждения исчезают

Хм, сам Text вызывает только sync() в onBeforeRender, который _не должен_ срабатывать, если visible=false.

Доступен ли ваш код оболочки LabelView где-нибудь, где я могу заглянуть?

Это часть проекта с закрытым исходным кодом

но вот соответствующий класс, которого может быть достаточно

import {Mesh, MeshBasicMaterial} from "three";
import R from "../../../../../../../../../../resources/Namespace";
import BaseView, {ViewType} from "./BaseView";
import {Text} from "troika-three-text";
import {GeometryInstances} from "../instances/GeometryInstances";
import {MaterialInstances} from "../instances/MaterialInstances";

export enum TextAlign {
    left = "left",
    right = "right",
    center = "center",
    justify = "justify",
}

export enum HorizontalAlign {
    left = "left",
    right = "right",
    center = "center",
}

export enum VerticalAlign {
    top = "top",
    topBaseline = "top-baseline",
    middle = "middle",
    bottomBaseline = "bottom-baseline",
    bottom = "bottom",
}

export interface ILabelData {
    content: string;
    fontFace?: string;
    fontSize?: number;
    alignment?: TextAlign;
    horizontalAlign?: HorizontalAlign;
    verticalAlign?: VerticalAlign;
    color?: string;
    opacity?: number;
    backgroundColor?: string;
    highlightable: boolean;
}

export default class LabelView extends BaseView {
    get viewObject() {
        return this._viewObject as any;
    }

    get content() {
        return this.textMesh.text;
    }

    set content(content: string) {
        if (content !== this.textMesh.text) {
            this.textMesh.text = content;
            this.textMesh.visible = !!content;

            this.syncIfVisible();
        }
    }

    private syncIfVisible() {
        // Better for perf: https://github.com/protectwise/troika/issues/112
        if (this.textMesh?.text && this.textMesh?.visible && this._isVisible) {
            this.textMesh.sync();
        }
    }

    set textAlign(alignment: TextAlign) {
        this.textMesh.textAlign = alignment;
        this.syncIfVisible();
    }

    set horizontalAlign(alignment: HorizontalAlign) {
        this.textMesh.anchorX = alignment;
        this.syncIfVisible();
    }

    set verticalAlign(alignment: VerticalAlign) {
        this.textMesh.anchorY = alignment;
        this.syncIfVisible();
    }

    private backgroundMesh: Mesh | undefined;
    private readonly textMesh: any;
    private readonly foregroundColor: string;
    private highlightable: boolean;

    constructor(labelData: ILabelData) {
        super(ViewType.Label);

        this.foregroundColor = labelData.color || R.colors.elements.labels.foreground;

        this.highlightable = labelData.highlightable;

        if (labelData.backgroundColor) {
            this.textMesh = this.createTextMesh(
                labelData.content,
                labelData.fontFace,
                labelData.fontSize,
                labelData.alignment,
                labelData.horizontalAlign,
                labelData.verticalAlign,
                this.foregroundColor,
                labelData.opacity,
                1);

            this.textMesh.addEventListener("synccomplete", () => {
                if (this.backgroundMesh) {
                    this._viewObject.remove(this.backgroundMesh);
                }

                if (this.textMesh.text) {
                    const bounds = this.textMesh.textRenderInfo.blockBounds;
                    this.backgroundMesh =
                        this.createBackgroundBox(bounds[0], bounds[1], bounds[2], bounds[3], 0);
                    this._viewObject.add(this.backgroundMesh);
                }
            });

        } else {
            this.textMesh = this.createTextMesh(
                labelData.content,
                labelData.fontFace,
                labelData.fontSize,
                labelData.alignment,
                labelData.horizontalAlign,
                labelData.verticalAlign,
                this.foregroundColor,
                labelData.opacity,
                0);
        }

        this.syncIfVisible();

        this._viewObject.add(this.textMesh);
    }

    public onFrameRendered(elapsedTime: number) {
        if (this.highlightable) {
            this.setLabelHighlightState();
        }
    }

    private setLabelHighlightState() {
        const labelMaterial = this.textMesh.material as MeshBasicMaterial;
        if (this._isHighlighted) {
            labelMaterial.color.set(R.colors.elements.labels.highlighted);
        } else {
            labelMaterial.color.set(this.foregroundColor);
        }
    }

    private createTextMesh(content: string,
                           fontFace = R.layout.labels.font_face.regular,
                           fontSize = R.layout.labels.font_size,
                           textAlign = TextAlign.center,
                           horizontalAlign = HorizontalAlign.center,
                           verticalAlign = VerticalAlign.middle,
                           color: string,
                           opacity = 1,
                           zLevel: number) {
        const labelMesh = new Text();

        labelMesh.font = fontFace;
        labelMesh.text = content || "";
        labelMesh.fontSize = fontSize;
        labelMesh.position.z = zLevel;
        labelMesh.color = color;
        labelMesh.textAlign = textAlign;
        labelMesh.anchorX = horizontalAlign;
        labelMesh.anchorY = verticalAlign;

        labelMesh.material.opacity = opacity;
        labelMesh.name = "LabelView";

        return labelMesh;
    }

    private createBackgroundBox(startX: number, startY: number, endX: number, endY: number, zLevel: number) {
        const paddingLeft = 1;
        const paddingRight = 2;
        const paddingTop = 1;
        const paddingBottom = 0;

        const width = Math.abs(startX) + Math.abs(endX) + paddingLeft + paddingRight;
        const height = Math.abs(startY) + Math.abs(endY) + (paddingTop + paddingBottom);

        const geometry = GeometryInstances.getInstance().getPlaneGeometryInstance(width, height);
        const material = MaterialInstances.getInstance().backgroundColorMaterial;
        const mesh = new Mesh(geometry, material);

        const posX = ((startX + endX) / 2) + (paddingLeft / 4);
        const posY = ((startY + endY) / 2) - (paddingBottom);

        // The z level of element in accordance with standards defined in resources
        mesh.position.set(posX, posY, zLevel);
        mesh.name = "LabelBackgroundBox";

        return mesh;
    }
}

Хм, я подозреваю, что syncIfVisible() вызывается до того, как для .visible установлено значение false, но трудно сказать наверняка, не зная, как работает ваша система просмотра.

Еще я заметил, что вы выполняете вызовы syncIfVisible после каждого изменения отдельного свойства (content, textAlign, horizontalAlign и т. д.), что будет вызывать больше вызовов работника, чем необходимо. Если ваша система просмотра имеет жизненный цикл, в котором вы можете выполнить один вызов синхронизации после установки всех отдельных свойств, это было бы намного лучше.

Из того, что вы описали, я думаю, что это предупреждение ведет себя так, как ожидалось; он правильно выделил проблему с производительностью. Я закрываю этот вопрос; не стесняйтесь открыть его снова, если вы считаете иначе. Спасибо!

Просто возвращаюсь к этому

Так что получается, что в моей сцене легко может быть более 1000 экземпляров текста. Но там просто не все видно одновременно

Многие из них просто появляются при наведении мыши на определенные объекты.

Поэтому мне интересно, какой лучший путь вперед здесь:

  1. создавать экземпляры только для видимого текста, а затем размонтировать, как только он станет невидимым?
  2. вместо этого использовать CSS-объекты ThreeJS?

Лично я бы остановился на первом варианте. Я могу ошибаться, но я не думаю, что есть какая-то польза от присутствия всех этих скрытых объектов-меток в графе сцены.

Понятно

Мне нужно иметь возможность быстро отображать их при наведении мыши на объекты

Вы бы порекомендовали просто уничтожить их после использования и создать новые при наведении или вместо этого просто удалить их из сцены threeJs?

Честно говоря, я не думаю, что будет заметна разница в любом случае. Я бы начал с того, чем проще всего управлять и оптимизировать, только если вы заметите проблему.

Лично я много использовал подход создания/уничтожения, и для меня это всегда достаточно быстро.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги