我正在使用for
循环遍历基本的JSON对象。 JSON如下:
{
"1": {
"project_name": "Example Project Name 1",
"client_name": "John Doe"
},
"2": {
"project_name": "Example Project Name 2",
"client_name": "John Doe"
},
/// -------
}
我遇到的问题是循环浏览时。我正在尝试使用.when()
和.then()
进行循环-ajax()
调用按预期方式同步进行,但是所说的ajax()
的 input 是始终是JSON
的最后一个索引。
function bulkUploadGo() {
var def = $.when();
for (var i = 1; i < Object.keys(projects_json).length + 1; i++) {
var project = Object(projects_json)[i];
// THIS WILL LOOP INSTANTLY -- SO I WILL SEE 1 - X INSTANTLY
console.log(project);
def = def.then(function () {
// THIS DISPLAYS SYNCHRONOUSLY, BUT IS ALWAYS SET TO THE LAST INDEX BECAUSE OF INSTANT LOOP ABOVE
console.log(project);
return prepareLayer(project);
});
}
}
function prepareLayer(project) {
return $.ajax({
type: "POST",
url: "/app/ajax/calls/process_project.php",
dataType: 'html',
data: {project: project}
}).then(function (data) {
var obj = JSON.parse(data);
// Do stuff
});
}
显然,我认为这是错误的,因为def = def.then(function () {
直接位于for
循环内,它将“保留”直到满足return
。我只是不明白为什么为什么错了,解决方案是什么!如何与脚本的其余部分同步地将project
正确地传递到prepareLayer(project)
中?我知道我的逻辑有缺陷,我只是看不见树林。
为了解释结果,以下是console.log()
的样子-蓝色区域是立即发生的事,其余区域是def.then(function () {
答案 0 :(得分:2)
您可能想代替Promise.all,同时跟踪各个任务的进度。还要注意,现代浏览器丝毫不需要在这里使用jQuery,您所做的一切都已经具有普通的JS API:
const APIEndpoint = `/app/ajax/calls/process_project.php`;
const yourData = { ...... };
const dataKeys = Object.keys(yourData);
const progressBar = new IncrementalProgressBar(dataKeys.length);
/**
* You're constantly posting to the same thing: let's make that a function.
*/
function postData(data = {}) {
return fetch(APIEndpoint, {
method: `POST`,
headers: {
"Content-Type": `application/json`
},
body: JSON.stringify(data)
});
}
/**
* Turn {yourData,key} into a promise around posting your data.
*/
function keyToPromise(key) {
return new Promise((resolve, reject) => {
const data = yourData[key];
postData(data)
.then(result => {
progressBar.increment();
resolve(result);
})
.catch(error => {
progressBar.increment({error: `${key} failed`});
reject(error);
});
};
}
// And now we just... run through all the things
Promise
.all(dataKeys.map(keyToPromise)))
.then(result => moveOnWhenDone())
.catch(error => handleException());
答案 1 :(得分:1)
这里有三种方法,并具有不同的并行化级别。
要一一上传并一一处理:
const bulkUpload = async(arr,processResponse=identity)=>{
for (let el in arr) {
const response = await upload(el)
await processResponse(response)
}
}
bulkUpload(projects.values, processResponse).then(...)
要并行上传并一一处理,我们将收到所有回复:
const bulkUpload = async(arr)=>await Promise.allSettled(arr.map(upload))
bulkUpload(projects.values).then((allResponses) => /* process the responses */)
要并行上传并处理每个响应,请执行以下操作:
const uploadAndProcess = (el) => upload(el).then(processResponse)
const bulkUpload = async(arr)=>await Promise.allSettled(arr.map(uploadAndProcess))
bulkUpload(projects.values)
样板
const projects = { "1": { "project_name": "P1", "client_name": "C1" }, "2": { "project_name": "P2", "client_name": "C2" }, }
const identity = (x)=>x
cont URL = '/app/ajax/calls/process_project.php'
const upload = (item)=>fetch(URL, requestOptions(item))
const requestOptions = (project)=>({ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ project }) })