KnockoutJS - 首先运行,扩展程序或订阅(手动设置或其他方式),如果它们被覆盖怎么办?

KnockoutJS - which runs first, extenders or subscriptions (manually set up or otherwise) and what about if they're overwritten?

这似乎是一个相当简单的问题,但我在任何地方都找不到很多没有矛盾的答案或解释。请参阅下面的 class;

export class Person {
    FirstName: KnockoutObservable<string>;
    Surname: KnockoutObservable<string>;
    FullName: KnockoutComputed<string>;
    SurnameExternalReference: KnockoutObservable<string>;

    constructor(data) {
        this.Name = ko.observable(data.Name).extend(someExtender: logChange);
        this.Surname = ko.observable(data.SurnameName).extend(someExtender: logChange);
        this.FullName = ko.copmuted(() => {
            return this.FirstName() + " " + this.Surname();
        }, this);
        this.SurnameExternalReference = ko.observable();

        this.Surname.subscribe(() => {
             //function here tests an external ko array of people for that surname 
             //and assigns this.SurnameExternalReference to that observable.
             //e.g.  - then sets sub back up as below only if found, otherwise this.SurnameExternalReference = null
             this.SurnameExternalReference = external.Surname;
             this.SurnameExternalReference.subscribe(() => {
                 this.Surname(this.SurnameExternalReference());
                 });

            });

        this.SurnameExternalReference.subscribe(() => {
            this.Surname(this.SurnameExternalReference());
        });
    }
}

我写这篇文章仅供参考,我的实际 viewModel 非常复杂并且不可能 post,但它确实(并且需要)这样做。 logChange 是一个测试输入并记录更改(如果有效)的函数,否则不写入新值(或记录更改)。

所以我的问题是,如果外部姓氏属性改变了,扩展器和函数的调用顺序是什么?请记住,在姓氏订阅中 this.SurnameExternalReference 继承了 external.surname 的扩展符。

是否总是在订阅之前调用扩展程序?订阅是按照设置的顺序调用的(我发现很多人都同意顺序是相当随机的并且按照设置的顺序)?

如果 observable 被外部覆盖,它是继承外部的顺序 sub/extender 还是添加到末尾?

相当复杂的问题,如果感到困惑,请提出任何 questions/post 个场景。

编辑:extenders/subscriptions 是否可以异步 运行 或它们只能 运行 同步?

Pretty complicated question

同意。部分原因是您的代码示例做了一些它可能不应该做的事情。

Are subscriptions called in order they're set

是的。

Are extenders always called before subscriptions

扩展器总是有第一个机会 "do something" 使用新创建的可观察对象。例如:

ko.extenders.logChange = function(obs, log) {
    if (log) obs.subscribe(console.log); // 1
    return obs;
};

const myName = ko.observable("Jane").extend({ logChange: true });
myName.subscribe(console.log); // 2

先附加扩展器创建的订阅,做第一个日志。当然,您可以在扩展程序函数中做各种奇怪的事情,这意味着永远没有保证。这个人为的例子交换了日志的顺序:

ko.extenders.logChange = function(obs, log) {
    if (log) setTimeout(() => obs.subscribe(console.log)); // 2
    return obs;
};

const myName = ko.observable("Jane").extend({ logChange: true });
myName.subscribe(console.log); // 1

对于您具体的更复杂的情况,我建议您在代码中放置一些断点并更新可观察对象以研究评估依赖项的顺序。

如果这不能帮助您解决实际问题,您可能需要提供一个可运行的示例来说明您尝试实现的逻辑。

注意:在另一个订阅创建订阅时,最好处置较早创建的订阅以防止出现奇怪的行为。