gpt4 book ai didi

javascript - Knockout JS - Promise 递归

转载 作者:行者123 更新时间:2023-12-02 23:59:51 27 4
gpt4 key购买 nike

我遇到了一种情况,我必须更新绑定(bind)到 HTML 元素的 Knockout 可观察量,并且其值正在通过异步操作(从服务器获取)进行更新。

我编写了以下示例代码:

const viewModel = function() {
const self = this;

self.fetchResults = function() {
const id = ko.observable(0);
fetch("https://jsonplaceholder.typicode.com/photos")
.then(function(response) {
return response.json();
})
.then(function(data) {
id(data.length);
console.log(id());
})
return id;
};
};

ko.applyBindings(new viewModel());
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>
<div data-bind="text: fetchResults()"></div>

它正在创建一个无限递归循环。

Knockout 是否会重复调用该函数,因为值正在异步函数内更新?此问题的根本原因是什么?

TIA!

编辑:

我的页面上有多个 HTML 元素,请求将不同的信息绑定(bind)到它们,例如,

<div data-bind="text: fetchResults('some-url')"></div>
<div data-bind="text: fetchResults('some-different-url')"></div>
<div data-bind="text: fetchResults('another-url-altogether')"></div>

这意味着我需要在我所做的 fetchResults 函数中创建可观察的内容(如果我的理解有误,请纠正我:))

最佳答案

问题是,由于您使用的是表达式,因此该函数在渲染时运行,返回一个可观察值。当可观察值的值发生变化时,它会使 View 的该部分再次渲染,从而再次调用该函数,从而永远循环。

您在评论中说过:

Actually I need to call this method multiple times for different fetch URIs in the same page, and bind to separate HTML elements.

...并将此示例添加到问题中:

<div data-bind="text: fetchResults('some-url')"></div>
<div data-bind="text: fetchResults('some-different-url')"></div>
<div data-bind="text: fetchResults('another-url-altogether')"></div>

这确实改变了一些事情。我可能会使用自定义绑定(bind)而不是函数:

ko.bindingHandlers.textFetch = {
update(element, valueAccessor) {
const url = ko.unwrap(valueAccessor());
element.textContent = "0";
fetch(url)
.then((response) => {
if (!response.ok) {
throw new Error("HTTP error " + response.status);
}
return response.json();
})
.then((data) => {
element.textContent = data.length;
});
}
};
const viewModel = function() {
};

ko.applyBindings(new viewModel());
<div data-bind="textFetch: 'https://jsonplaceholder.typicode.com/photos'"></div>
<div data-bind="textFetch: 'https://jsonplaceholder.typicode.com/posts'"></div>
<div data-bind="textFetch: 'https://jsonplaceholder.typicode.com/comments'"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<小时/>

但是如果您想让它与当前代码更相似,请保留 url 的可观察量的缓存:

const viewModel = function() {
const self = this;
// In a modern environment, `observables` could be a Map rather than an object
const observables = Object.create(null);

self.fetchResults = function(url) {
// Get the observable if we have it
let id = observables[url];
if (!id) {
// We don't, create and remember one, do the fetch
id = observables[url] = ko.observable(0);
fetch(url)
.then(function(response) {
return response.json();
})
.then(function(data) {
id(data.length);
})
}
return id;
};
};

ko.applyBindings(new viewModel());
<div data-bind="text: fetchResults('https://jsonplaceholder.typicode.com/photos')"></div>
<div data-bind="text: fetchResults('https://jsonplaceholder.typicode.com/posts')"></div>
<div data-bind="text: fetchResults('https://jsonplaceholder.typicode.com/comments')"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.2/knockout-min.js"></script>

<小时/>

附注:您不会在 fetch 回调中检查是否成功。你不是唯一一个,我什至可以说 fetch API 设计得很糟糕,因为我看到这把枪几乎每天都在 SO 上发射。我有written it up在我贫血的小博客上,但基本上,您需要添加:

if (!response.ok) {
throw new Error("HTTP error " + response.status);
}

...在您的履行处理程序中。

关于javascript - Knockout JS - Promise 递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55225175/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com