延迟异步计算的可观察量

时间:2014-12-03 23:33:23

标签: javascript jquery knockout.js knockout-2.0

我一直疯狂地试图弄明白这个。我已经看到很多混淆且难以实现的例子,当异步调用完成时,在Knockout中填充计算的observable,但我似乎无法使用模块显示模式使其工作。

我试图创建一个只读的可观察对象,因为这就是我所需要的。如果我不需要匿名函数来运行来发出请求,我甚至不会制作一个可观察的内容。这是我的观点模型:

eh.vm.skills = function () {

    //#region Public Variables

    var skills = ko.computed({
            read: function () {
                $.get("http://horodyski.me/api/skills", function (data) {
                    return data;
                });
            },
            deferEvaluation: true
        }),
    //#endregion


    //#region Public Interface

    return {
        skills: skills
    }

    //#endregion
};

这是HTML绑定:

<ul class="skills skills-top" id="skills" data-bind="foreach: skills">
    <li>
        <i data-bind="text: $index"> </i>
        <span data-bind="text: $data.Title"></span>
    </li>
</ul>
<script src="//cdn.horodyski.me/js/vm.js"></script>
<script>
    ko.applyBindings(eh.vm.skills, $("#skills")[0]);
</script>

我想做的是创建skills变量,获取数据并将其返回。数据已经以数组形式返回(例如:[{Title: "ABC"}])但它似乎没有绑定。我尝试使用$.when().then()代替(因为我更喜欢),但即使延迟计算值,它仍然无法更新。

对我来说,真正复杂的部分是变量范围。模块显示模式在涉及范围时很糟糕。我已经绞尽脑汁待了3个小时......如果有人能指引我朝着正确的方向前进,我们将不胜感激。

编辑使用Knockout 3.1(如果有帮助)

1 个答案:

答案 0 :(得分:6)

你的read回调都错了。

回调:

function (data) {
    return data;
}

是死代码,它将数据返回到调用此回调的jQuery函数,该函数将对此无效。

您需要返回延迟本身:

read: function () {
    return $.get("http://horodyski.me/api/skills");
}

您还需要这里的异步扩展程序:http://smellegantcode.wordpress.com/2012/12/10/asynchronous-computed-observables-in-knockout-js/

ko.extenders.async = function(computedDeferred, initialValue) {
    var plainObservable = ko.observable(initialValue), currentDeferred;
    plainObservable.inProgress = ko.observable(false);

    ko.computed(function() {
        if (currentDeferred) {
            currentDeferred.reject();
            currentDeferred = null;
        }

        var newDeferred = computedDeferred();
        if (newDeferred && (typeof newDeferred.done == "function")) {
            plainObservable.inProgress(true);
            currentDeferred = $.Deferred().done(function(data) {
                plainObservable.inProgress(false);
                plainObservable(data);
            });
            newDeferred.done(currentDeferred.resolve);
        } else {
            plainObservable(newDeferred);
        }
    });

    return plainObservable;
};

用过:

var skills = ko.computed(...).extend({ async: null });

如果要在传递给视图之前挂钩JSON:

var skillsJson = ko.computed(...).extend({ async: null });
var skills = ko.computed(function () {
    return transformData(skillsJson());
};

或者:

var skills = ko.computed(function () {
        return $.get("url").then(function (data) {
            return transform(data);
        });
    });