所以基本上我有一个非常简单的计数器,可以从5个不同的位置加载JSON文件并计算条目数:
let count = {
1: 0,
2: 0,
3: 0,
4: 0,
5: 0,
total: 0
};
let url = {
1: "https://jsonplaceholder.typicode.com/posts",
2: "https://jsonplaceholder.typicode.com/comments",
3: "https://jsonplaceholder.typicode.com/albums",
4: "https://jsonplaceholder.typicode.com/todos",
5: "https://jsonplaceholder.typicode.com/users"
};
function fetchJSONList(url) {
return new Promise(function(resolve, reject) {
fetch(url)
.then(response => { return response.json(); })
.then(resolve)
.catch(reject);
});
}
function checkAll() {
return new Promise(function(resolve, reject) {
$.each(url, function(key) {
fetchJSONList(url[key])
.then(list => {
if ($.isEmptyObject(list)) {
const spanID = "#api-" + key;
$(spanID).text(0);
}
$.each(list, function() {
count[key]++;
count.total++;
const spanID = "#api-" + key;
$(spanID).text(count[key]);
});
})
.catch(reject);
});
resolve();
});
}
checkAll()
.then($("#count-total").text(count.total))
.catch(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="site-list">
<li><span>API 1: </span><span id="api-1">Loading...</span></li>
<li><span>API 2: </span><span id="api-2">Loading...</span></li>
<li><span>API 3: </span><span id="api-3">Loading...</span></li>
<li><span>API 4: </span><span id="api-4">Loading...</span></li>
<li><span>API 5: </span><span id="api-5">Loading...</span></li>
</ul>
<span>Total: </span><span id="count-total">Loading...</span>
如您所见,现在脚本加载后,总金额立即更新为“ 0”(即,函数checkAll()
返回的诺言立即得到解决)。但是,我希望总值仅在$.each
完成对url
变量的迭代之后才更新。
有什么想法怎么做?
编辑:因此考虑T.J.人群的答案,
let count = {
1: 0,
2: 0,
3: 0,
4: 0,
5: 0,
total: 0
};
let url = {
1: "https://jsonplaceholder.typicode.com/posts",
2: "https://jsonplaceholder.typicode.com/comments",
3: "https://jsonplaceholder.typicode.com/albums",
4: "https://jsonplaceholder.typicode.com/todos",
5: "https://jsonplaceholder.typicode.com/users"
};
function fetchJSONList(url) {
return new Promise(function(resolve, reject) {
fetch(url)
.then(response => { return response.json(); })
.then(resolve)
.catch(reject);
});
}
Promise
.all(
Object.entries(url).map(([key, value]) => {
fetchJSONList(value)
.then(list => {
if ($.isEmptyObject(list)) {
const spanID = "#api-" + key;
$(spanID).text(0);
}
$.each(list, function() {
count[key]++;
count.total++;
const spanID = "#api-" + key;
$(spanID).text(count[key]);
});
})
})
)
.then($("#count-total").text(count.total))
.catch(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="site-list">
<li><span>API 1: </span><span id="api-1">Loading...</span></li>
<li><span>API 2: </span><span id="api-2">Loading...</span></li>
<li><span>API 3: </span><span id="api-3">Loading...</span></li>
<li><span>API 4: </span><span id="api-4">Loading...</span></li>
<li><span>API 5: </span><span id="api-5">Loading...</span></li>
</ul>
<span>Total: </span><span id="count-total">Loading...</span>
很高兴,仍然没有运气。
答案 0 :(得分:4)
但是,我希望总值仅在
$.each
完成对url
变量的迭代之后才更新。
是的。 :-)只是$.each
不等待异步过程开始完成。
如果您希望所有这些同时运行,请使用map
来收集承诺,并使用Promise.all
等待它们全部兑现(或其中一个被拒绝):>
function checkAll() {
return Promise.all(Object.entries(url).map(([key, value]) =>
fetchJSONList(value)
.then(list => {
if ($.isEmptyObject(list)) {
const spanID = "#api-" + key;
$(spanID).text(0);
}
$.each(list, function() {
count[key]++;
count.total++;
const spanID = "#api-" + key;
$(spanID).text(count[key]);
});
})
));
}
您还需要在此处将呼叫固定为then
:
.then($("#count-total").text(count.total))
该调用 $(/*...*/).text(/*...*/)
,并将返回值传递到then
中。您要传递then
一个函数:
.then(() => $("#count-total").text(count.total))
此外,new Promise
中没有理由使用fetchJSONList
;您已经已经有了一个诺言,只需兑现诺言。但是您确实需要处理fetch
API footgun,它不会因HTTP错误(只是网络错误)而拒绝:
function fetchJSONList(url) {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error("HTTP error " + response.status);
}
return response.json();
});
}
将它们放在一起:
let count = {
1: 0,
2: 0,
3: 0,
4: 0,
5: 0,
total: 0
};
let url = {
1: "https://jsonplaceholder.typicode.com/posts",
2: "https://jsonplaceholder.typicode.com/comments",
3: "https://jsonplaceholder.typicode.com/albums",
4: "https://jsonplaceholder.typicode.com/todos",
5: "https://jsonplaceholder.typicode.com/users"
};
function fetchJSONList(url) {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error("HTTP error " + response.status);
}
return response.json();
});
}
function checkAll() {
return Promise.all(Object.entries(url).map(([key, value]) =>
fetchJSONList(value)
.then(list => {
if ($.isEmptyObject(list)) {
const spanID = "#api-" + key;
$(spanID).text(0);
}
$.each(list, function() {
count[key]++;
count.total++;
const spanID = "#api-" + key;
$(spanID).text(count[key]);
});
})
));
}
checkAll()
.then(() => $("#count-total").text(count.total))
.catch(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="site-list">
<li><span>API 1: </span><span id="api-1">Loading...</span></li>
<li><span>API 2: </span><span id="api-2">Loading...</span></li>
<li><span>API 3: </span><span id="api-3">Loading...</span></li>
<li><span>API 4: </span><span id="api-4">Loading...</span></li>
<li><span>API 5: </span><span id="api-5">Loading...</span></li>
</ul>
<span>Total: </span><span id="count-total">Loading...</span>
如果要在开始下一个之前等待它们中的每个完成,请构建带有循环的promise链:
function checkAll() {
let p = Promise.resolve();
for (const [key, value] of Object.entries(url)) {
p = p.then(() => fetchJSONList(value))
.then(list => {
if ($.isEmptyObject(list)) {
const spanID = "#api-" + key;
$(spanID).text(0);
}
$.each(list, function() {
count[key]++;
count.total++;
const spanID = "#api-" + key;
$(spanID).text(count[key]);
});
});
}
return p;
}
let count = {
1: 0,
2: 0,
3: 0,
4: 0,
5: 0,
total: 0
};
let url = {
1: "https://jsonplaceholder.typicode.com/posts",
2: "https://jsonplaceholder.typicode.com/comments",
3: "https://jsonplaceholder.typicode.com/albums",
4: "https://jsonplaceholder.typicode.com/todos",
5: "https://jsonplaceholder.typicode.com/users"
};
function fetchJSONList(url) {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error("HTTP error " + response.status);
}
return response.json();
});
}
function checkAll() {
let p = Promise.resolve();
for (const [key, value] of Object.entries(url)) {
p = p.then(() => fetchJSONList(value))
.then(list => {
if ($.isEmptyObject(list)) {
const spanID = "#api-" + key;
$(spanID).text(0);
}
$.each(list, function() {
count[key]++;
count.total++;
const spanID = "#api-" + key;
$(spanID).text(count[key]);
});
});
}
return p;
}
checkAll()
.then(() => $("#count-total").text(count.total))
.catch(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="site-list">
<li><span>API 1: </span><span id="api-1">Loading...</span></li>
<li><span>API 2: </span><span id="api-2">Loading...</span></li>
<li><span>API 3: </span><span id="api-3">Loading...</span></li>
<li><span>API 4: </span><span id="api-4">Loading...</span></li>
<li><span>API 5: </span><span id="api-5">Loading...</span></li>
</ul>
<span>Total: </span><span id="count-total">Loading...</span>
或者如果您的环境支持它们,请使用async
函数:
async function checkAll() {
for (const [key, value] of Object.entries(url)) {
const list = await fetchJSONList(value);
if ($.isEmptyObject(list)) {
const spanID = "#api-" + key;
$(spanID).text(0);
}
$.each(list, function() {
count[key]++;
count.total++;
const spanID = "#api-" + key;
$(spanID).text(count[key]);
});
}
}
let count = {
1: 0,
2: 0,
3: 0,
4: 0,
5: 0,
total: 0
};
let url = {
1: "https://jsonplaceholder.typicode.com/posts",
2: "https://jsonplaceholder.typicode.com/comments",
3: "https://jsonplaceholder.typicode.com/albums",
4: "https://jsonplaceholder.typicode.com/todos",
5: "https://jsonplaceholder.typicode.com/users"
};
function fetchJSONList(url) {
return fetch(url)
.then(response => {
if (!response.ok) {
throw new Error("HTTP error " + response.status);
}
return response.json();
});
}
async function checkAll() {
for (const [key, value] of Object.entries(url)) {
const list = await fetchJSONList(value);
if ($.isEmptyObject(list)) {
const spanID = "#api-" + key;
$(spanID).text(0);
}
$.each(list, function() {
count[key]++;
count.total++;
const spanID = "#api-" + key;
$(spanID).text(count[key]);
});
}
}
checkAll()
.then(() => $("#count-total").text(count.total))
.catch(console.log);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="site-list">
<li><span>API 1: </span><span id="api-1">Loading...</span></li>
<li><span>API 2: </span><span id="api-2">Loading...</span></li>
<li><span>API 3: </span><span id="api-3">Loading...</span></li>
<li><span>API 4: </span><span id="api-4">Loading...</span></li>
<li><span>API 5: </span><span id="api-5">Loading...</span></li>
</ul>
<span>Total: </span><span id="count-total">Loading...</span>
答案 1 :(得分:0)
let count = {
1: 0,
2: 0,
3: 0,
4: 0,
5: 0,
total: 0
};
let url = {
1: "https://jsonplaceholder.typicode.com/posts",
2: "https://jsonplaceholder.typicode.com/comments",
3: "https://jsonplaceholder.typicode.com/albums",
4: "https://jsonplaceholder.typicode.com/todos",
5: "https://jsonplaceholder.typicode.com/users"
};
function fetchJSONList(url) {
return new Promise(function(resolve, reject) {
fetch(url)
.then(response => { return response.json(); })
.then(resolve)
.catch(reject);
});
}
function checkAll() {
return new Promise(function(resolve, reject) {
$.each(url, function(key) {
fetchJSONList(url[key])
.then(list => {
if ($.isEmptyObject(list)) {
const spanID = "#api-" + key;
$(spanID).text(0);
}
$.each(list, function() {
count[key]++;
count.total++;
const spanID = "#api-" + key;
$(spanID).text(count[key]);
$('#count-total').text(count.total);
});
})
.catch(reject);
});
resolve(count);
});
}
checkAll();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="site-list">
<li><span>API 1: </span><span id="api-1">Loading...</span></li>
<li><span>API 2: </span><span id="api-2">Loading...</span></li>
<li><span>API 3: </span><span id="api-3">Loading...</span></li>
<li><span>API 4: </span><span id="api-4">Loading...</span></li>
<li><span>API 5: </span><span id="api-5">Loading...</span></li>
</ul>
<span>Total: </span><span id="count-total">Loading...</span>
我的想法是直接在循环中渲染总计。我在循环内将您的分配总数转移了。并仅调用该函数。希望它能工作。
答案 2 :(得分:0)
您在任何诺言兑现之前就下定决心。因此解决方案是使用Promise.all
下面的代码片段可以为您提供帮助(我在显示总计之前延迟了一秒钟,因此您可以清楚地看到行为)
let count = {
1: 0,
2: 0,
3: 0,
4: 0,
5: 0,
total: 0
}
let url = {
1: 'https://jsonplaceholder.typicode.com/posts',
2: 'https://jsonplaceholder.typicode.com/comments',
3: 'https://jsonplaceholder.typicode.com/albums',
4: 'https://jsonplaceholder.typicode.com/todos',
5: 'https://jsonplaceholder.typicode.com/users'
}
function fetchJSONList(key) {
return new Promise(function(resolve, reject) {
fetch(url[key])
.then(response => {
return response.json()
})
.then(list => resolve([key, list]))
.catch(reject)
})
}
function checkAll() {
return new Promise(function(resolve, reject) {
Promise.all(Object.keys(url).map(key => fetchJSONList(key)))
.then(results => {
results.forEach(([key, list = []]) => {
if ($.isEmptyObject(list)) {
const spanID = '#api-' + key
$(spanID).text(0)
}
$.each(list, function() {
count[key]++
count.total++
const spanID = '#api-' + key
$(spanID).text(count[key])
})
})
setTimeout(() => {
$('#count-total').text(count.total)
resolve()
}, 1000)
})
.catch(reject)
})
}
checkAll()
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul id="site-list">
<li><span>API 1: </span><span id="api-1">Loading...</span></li>
<li><span>API 2: </span><span id="api-2">Loading...</span></li>
<li><span>API 3: </span><span id="api-3">Loading...</span></li>
<li><span>API 4: </span><span id="api-4">Loading...</span></li>
<li><span>API 5: </span><span id="api-5">Loading...</span></li>
</ul>
<span>Total: </span><span id="count-total">Loading...</span>