jQuery .when() .then() promise 不遵守 for 循环
jQuery .when() .then() promise not adhering inside for loop
我正在使用 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()
调用按预期同步进行,但是 input 表示 ajax()
始终是 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
循环内所以它会 "hold it" 直到 return
被满足。我只是不明白为什么我错了,解决办法是什么!如何与脚本的其余部分同步正确地将 project
传递给 prepareLayer(project)
?我知道我的逻辑有问题,就是见树不见林。
作为解释结果的参考,这里是 console.log()
的样子 -- 蓝色区域是立即发生的,其余的是 def.then(function () {
您可能希望使用 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());
以下是执行此操作的三种方法,具有不同的并行化级别。
要逐一上传,逐一处理:
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 }) })
我正在使用 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()
调用按预期同步进行,但是 input 表示 ajax()
始终是 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
循环内所以它会 "hold it" 直到 return
被满足。我只是不明白为什么我错了,解决办法是什么!如何与脚本的其余部分同步正确地将 project
传递给 prepareLayer(project)
?我知道我的逻辑有问题,就是见树不见林。
作为解释结果的参考,这里是 console.log()
的样子 -- 蓝色区域是立即发生的,其余的是 def.then(function () {
您可能希望使用 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());
以下是执行此操作的三种方法,具有不同的并行化级别。
要逐一上传,逐一处理:
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 }) })