I have a scenario where I have to delete attachments first and then upload new attachments. Here is my code:
var programs = this.UploadModel.getProperty("/programs/items");
//Delete files first
for(var i=0; i<filesToDelete.length; i ){
oThis._callAttachmentWS("DELETE", proj, filesToDelete[i]);
}
//Then save new files
for(var i=0; i<programs.length; i ){
oThis._callAttachmentWS("SAVE", proj, programs[i]);
}
How do I make the second for loop wait for the first loop to finish?
CodePudding user response:
Since the OP within the comments states ...
"... it calls a web service and the return is true or false"
"... the function is coming from another controller. It can be changed. Since it's an ajax call, then callback back is most likely supported"
... and looking at how ...
oThis._callAttachmentWS("DELETE", proj, filesToDelete[i]);
... respectively ...
oThis._callAttachmentWS("SAVE", proj, programs[i]);
... are being used, one could assume the _callAttachmentWS
method returns a Promise
.
Promise.all
and Promise.allSettled
are two methods each operating upon the states of a list of promises and returning a promise itself.
The next provided example code utilizes the latter method. The implementation also mocks the behavior of an asynchronous (promise returning) _callAttachmentWS
method. There are promise returning helper functions for the also mocked file save/delete tasks. The main task, called handleFileDeleteAndFileSave
, shows a possible solution of how one could handle the promise chain(s) ...
function callAttachmentWS(action, project, fileName) {
return new Promise(
(resolve, reject) => {
setTimeout(() => {
// file deletion completed.
resolve({ action, fileName });
}, 3000);
}
);
}
// var programs = this.UploadModel.getProperty("/programs/items");
// //Delete files first
// for(var i=0; i<filesToDelete.length; i ){
// oThis._callAttachmentWS("DELETE", proj, filesToDelete[i]);
// }
//
// //Then save new files
// for(var i=0; i<programs.length; i ){
// oThis._callAttachmentWS("SAVE", proj, programs[i]);
// }
function triggerFileActions(action, fileList) {
console.log(` trigger ${ action.toLowerCase() } files `);
// returns an array of promises.
return fileList.map(fileName =>
/*oThis._*/callAttachmentWS(action, 'my-project-name', fileName)
)
}
function deleteFiles(fileList) {
// returns a promise.
return Promise.allSettled(triggerFileActions('DELETE', fileList));
}
function saveFiles(fileList) {
// returns a promise.
return Promise.allSettled(triggerFileActions('SAVE', fileList));
}
function handleFileDeleteAndFileSave(deleteList, saveList) {
// returns a promise.
return deleteFiles(
deleteList
).then(deleteResultList => {
deleteResultList.forEach(result => console.log(result));
console.log('... delete files finished ...');
}).then(() => {
// returns a promise.
return saveFiles(
saveList
).then(saveResultList => {
saveResultList.forEach(result => console.log(result));
console.log('... save files finished ...');
}).then(() => ' handleFileDeleteAndFileSave is settled ');
});
}
const filesToDelete = ['foo', 'bar', 'baz'];
const programs = ['bizz', 'buzz'];
handleFileDeleteAndFileSave(
filesToDelete,
programs,
)
.then(status => console.log(status));
.as-console-wrapper { min-height: 100%!important; top: 0; }
As the above code shows, the properly timed handling of file delete/save is based on nested promise chains. In order to free the programmers' minds from writing and maintaining such structures the async ... await
syntax was introduced.
The next code example repeats the above code block, just in a more imperative programming style ...
async function callAttachmentWS(action, project, fileName) {
return new Promise(
(resolve, reject) => {
setTimeout(() => {
// file deletion completed.
resolve({ action, fileName });
}, 3000);
}
);
}
function triggerFileActions(action, fileList) {
console.log(` trigger ${ action.toLowerCase() } files `);
// returns an array of promises.
return fileList.map(fileName =>
callAttachmentWS(action, 'my-project-name', fileName)
)
}
async function deleteFiles(fileList) {
// returns a promise.
return Promise.allSettled(triggerFileActions('DELETE', fileList));
}
async function saveFiles(fileList) {
// returns a promise.
return Promise.allSettled(triggerFileActions('SAVE', fileList));
}
async function handleFileDeleteAndFileSave(deleteList, saveList) {
// handles promises (async functions) via `await` syntax,
// thus it makes it an async function too
// which (implicitly) returns a promise.
const deleteResultList = await deleteFiles(deleteList);
deleteResultList.forEach(result => console.log(result));
console.log('... delete files finished ...');
const saveResultList = await saveFiles(saveList);
saveResultList.forEach(result => console.log(result));
console.log('... save files finished ...');
return ' handleFileDeleteAndFileSave is settled ';
}
const filesToDelete = ['foo', 'bar', 'baz'];
const programs = ['bizz', 'buzz'];
(async function () {
const status =
await handleFileDeleteAndFileSave(filesToDelete, programs);
console.log(status);
}());
.as-console-wrapper { min-height: 100%!important; top: 0; }
CodePudding user response:
You can use async/await. Here is more about them