简体   繁体   中英

How can I run a function multiple times with a different parameter, but wait until all are finished to continue with my code logic using promises?

I'm uploading a CSV file to the server, then in the backend I split that file into multiple smaller files (because these files can get quite big). After uploading and splitting the file, I then want to process the file to insert some new data to the database.

All the logic works properly, however, I need to run some cleanup code after all files have finished processing. After researching for a while I found that I can make this happen by using Javascript promises.

I have always had problems understanding Javascript promises, it's the second night in a row that I stay up until past midnight to try and get this finished, so I don't think my understanding of Javascript promises will improve that much this soon, I just need to get this done.

Anyone with experience in Javascript promises, can you see what I'm doing wrong or what I'm missing? My code below is quite explanatory (I think).

 function sendAjaxRequest(data, callback, addUploadEvents = false) { return new Promise(function (resolve, reject) { let xhr = new XMLHttpRequest(); xhr.open('POST', ajaxurl); // when finished, we run our passed callback xhr.onload = callback; // only when uploading the file if ( addUploadEvents ) { xhr.addEventListener('loadstart', function() { console.log('uploading file'); }); xhr.addEventListener('progress', function(evt) { console.log('loaded: ' + evt.loaded + ', total: ' + evt.total); }); xhr.addEventListener('loadend', function() { console.log('file uploaded'); }); } // general events to catch errors xhr.addEventListener('timeout', function(e) { console.log('the request has timed out', e); reject(e); }); xhr.addEventListener('error', function(e) { console.log('the request returned an error', e); reject(e); }); xhr.addEventListener('abort', function(e) { console.log('the request was aborted', e); reject(e); }); // send the request xhr.send(data); }); } function uploadFile() { let data = new FormData(), f = document.querySelector('form [name="csv"]').files; data.append('csv', f[0]); // send the request let req = sendAjaxRequest(data, function() { if ( this.status === 200 ) { const response = JSON.parse(this.response); if ( ! response.success ) { console.log('error in the uploadFile request'); return false; } // once the file is uploaded, we want to split it into several smaller pieces splitToMultipleFiles(); } else { // should not reach this ever, I think I covered all problematic cases console.log('there was an error in the request', this); } }, true); // returning false to prevent the form from reloading the page return false; } function splitToMultipleFiles() { let data = new FormData(); // send the request let req = sendAjaxRequest(data, function() { if ( this.status === 200 ) { const response = JSON.parse(this.response); if ( ! response.success ) { console.log('error in the splitToMultipleFiles request'); return; } // response.data.files has an array of files I want to process in the backend one at a time let processingFiles = response.data.files.map(function(file) { return processFile(file); }); // wait until all files have been processed, then run some cleanup logic // the problem is, the promises are never resolved :( Promise.all(processingFiles).then(function() { console.log('all done, cleanup your mess'); }); } }); } function processFile(tempFile) { let data = new FormData(); data.append('temp-file', tempFile); // send the request return sendAjaxRequest(data, function() { if ( this.status === 200 ) { const response = JSON.parse(this.response); if ( ! response.success ) { console.log('error in the processFile request for file ' + tempFile); return; } console.log('file finished processing: ' + tempFile); } }); }

Well, I guess I will need to schedule a good course on Javascript promises as a next year objective.. for now, I was able to solve my dilemma like this, probably not the best way but it did work:

 function sendAjaxRequest(data, callback, addUploadEvents = false) { let xhr = new XMLHttpRequest(); xhr.open('POST', ajaxurl); // when finished, we run our passed callback xhr.onload = callback; // only when uploading the file if ( addUploadEvents ) { xhr.addEventListener('loadstart', function() { console.log('uploading file'); }); xhr.addEventListener('progress', function(evt) { console.log('loaded: ' + evt.loaded + ', total: ' + evt.total); }); xhr.addEventListener('loadend', function() { console.log('file uploaded'); }); } // general events to catch errors xhr.addEventListener('timeout', function(e) { console.log('the request has timed out', e); }); xhr.addEventListener('error', function(e) { console.log('the request returned an error', e); }); xhr.addEventListener('abort', function(e) { console.log('the request was aborted', e); }); // send the request xhr.send(data); } function uploadFile() { let data = new FormData(), f = document.querySelector('form [name="csv"]').files; data.append('csv', f[0]); // send the request let promise = new Promise(function(resolve, reject) { sendAjaxRequest(data, function() { if ( this.status === 200 ) { const response = JSON.parse(this.response); if ( ! response.success ) { console.log('error in the uploadFile request'); return false; } resolve(response.data); } else { // should not reach this ever, I think I covered all problematic cases console.log('there was an error in the request', this); reject(this.status); } }, true); }); promise.then(splitToMultipleFiles, function(err) { console.log('promise rejected', err); }); // returning false to prevent the form from reloading the page return false; } function splitToMultipleFiles() { let data = new FormData(); // send the request let promise = new Promise(function(resolve, reject) { sendAjaxRequest(data, function() { if ( this.status === 200 ) { const response = JSON.parse(this.response); if ( ! response.success ) { console.log('error in the splitToMultipleFiles request'); return; } // response.data.files has an array of files I want to process in the backend one at a time resolve(response.data.files); } else { reject(this.status); } }); }); promise.then(function(files) { let processingFiles = files.map(function (file) { return processFile(file); }); // wait until all files have been processed, then run some cleanup logic Promise.all(processingFiles).then(function () { console.log('all done, cleanup your mess'); }); }, function(err) { console.log('promise rejected', err); }); } function processFile(tempFile) { let data = new FormData(); data.append('temp-file', tempFile); // send the request return new Promise(function(resolve, reject) { sendAjaxRequest(data, function() { if ( this.status === 200 ) { const response = JSON.parse(this.response); if ( ! response.success ) { console.log('error in the processFile request for file ' + tempFile); return; } console.log('file finished processing: ' + tempFile); resolve(response.data); } else { reject(this.status); } }); }); }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM