[英]Knockout JS - Promise recursion
在這種情況下,我必須更新綁定到HTML元素的可觀察的可觀察對象,並且其值正在通過異步操作(從服務器中獲取)進行更新。
我編寫了以下示例代碼:
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>
它正在創建一個無限的遞歸循環。
敲除是否在異步函數中更新值而重復調用該函數? 可能是此問題的根本原因是什么?
TIA!
編輯:
我在頁面上有多個HTML元素,要求將不同的信息綁定到它們,例如,
<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
函數內部創建可觀察的(如果我的理解fetchResults
,請更正我:)
問題在於,由於您正在使用表達式,因此該函數將在render上運行,並返回一個可觀察的對象。 當可觀察對象的值更改時,它將使視圖的該部分再次呈現,從而再次調用該函數,並永遠循環。
在評論中,您說過:
實際上,我需要針對同一頁面中的不同提取URI多次調用此方法,並將其綁定到單獨的HTML元素。
...並將此示例添加到問題中:
<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>
那確實改變了一點。 我可能會使用自定義綁定而不是函數:
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上被觸發。 我已經在貧乏的小博客上寫下了它 ,但是基本上,您需要添加:
if (!response.ok) {
throw new Error("HTTP error " + response.status);
}
...在您的履行處理程序中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.