基本上,我有一个非常简单的计数器,它从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.Crowder的答案,
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>
欢迎还是没运气。
发布于 2020-07-20 09:21:14
但是,
希望只有在
$.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
;您已经有了一个承诺,只是将其链接在一起。但是,您确实需要处理它不拒绝HTTP的fetch
API footgun (只是网络错误):
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>
如果您想在启动下一个项目之前等待它们中的每一个完成,请使用一个循环构建一个承诺链:
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>
发布于 2020-07-20 09:25:18
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>
我的想法是直接在循环中呈现总数。我把你的任务调到循环里了。只调用函数。希望它能成功。
发布于 2020-07-20 10:07:00
你在承诺实现之前就已经解决了。所以解决方案是使用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>
https://stackoverflow.com/questions/62992255
复制相似问题