I need to determine whether I need to upload photos(calling upload API) sequentially or parallel.
Sequential means when you upload images(calling upload API), you wait for the first one to be resolved then display the image, before calling on the next upload API.
Parallel means when you upload images, you display whatever images is resolved first. So you can display simultaneously images since multiple response can be resolved here.
I wanted to have a condition whether to be sequential or parallel in just one uploadPhotos action.
The condition is to use sequential when it includes same filename like if you upload aa_11-01.jpg then you upload aa_11-02.jpg, else use parallel.
Always remember to only identify if its before the last -xxx
For example.
aa_11-01.jpg - aa_11
aa-11-01.jpg - aa-11
aa.jpg - aa
aa-12j-14kkk.jpg - aa-12j
test-a.jpg - test
test-b.jpg - test
Parallel
export const uploadPhotos =
({ photos, size, controller }) =>
async (dispatch) => {
photos.forEach(async (photo, index) => {
const formData = new FormData();
formData.append(photo?.imageFileName, photo?.imageFile)
dispatch({ type: constants.UPLOAD_PHOTOS_START, size });
try {
const response = await axios.post(
`${API_URL}/photos/upload`,
formData,
{
onUploadProgress({ loaded, total }) {
dispatch(setUploadProgress({ id: index, loaded, total }));
},
signal: controller.signal,
}
);
dispatch({
type: constants.UPLOAD_PHOTOS_SUCCESS,
payload: response.data,
});
} catch (error) {
dispatch({
type: constants.UPLOAD_PHOTOS_FAILURE,
payload: error,
});
}
});
};
Sequential
export const uploadPhotos =
({ photos, size, controller }) =>
async (dispatch) => {
for (const [index, photo] of photos.entries()) {
const formData = new FormData();
formData.append(photo?.imageFileName, photo?.imageFile)
dispatch({ type: constants.UPLOAD_PHOTOS_START, size });
try {
const response = await axios.post(
`${API_URL}/photos/upload`,
formData,
{
onUploadProgress({ loaded, total }) {
dispatch(setUploadProgress({ id: index, loaded, total }));
},
signal: controller.signal,
}
);
dispatch({
type: constants.UPLOAD_PHOTOS_SUCCESS,
payload: response.data,
});
} catch (error) {
dispatch({
type: constants.UPLOAD_PHOTOS_FAILURE,
payload: error,
});
}
}
};
Before making any requests, you could first analyse the filenames and group the array into subarrays, where a subarray has file names that have the pattern "name-sequence.ext" ("sequence" can be anything). Filenames that do not have this sequence part, will just end up as the only entry in a subarray.
Then mix the two loops, with the forEach as outer loop, and the for as inner loop:
export const uploadPhotos =
({ photos, size, controller }) =>
async (dispatch) => {
// Identify the part of the file name that excludes the (optional) sequence number
const keyedphotos = photos.map(photo => [photo.imageFileName.replace(/-\w+\.\w+$/, ""), photo]);
// Create a group for each such prefix
const map = new Map(keyedphotos.map(([key]) => [key, []]));
// Populate those groups
for (const [key, photo] of keyedphotos) map.get(key).push(photo)
// And extract those groups into an array (of subarrays)
const photoGroups = [...map.values()];
let index = 0; // Keep the index counter separate
photoGroups.forEach(async (photos) => { // Iterate the groups that can run in parallel
for (const photo of photos) { // Iterate the photos that should run sequentially
const id = index++; // Get the next unique id
const formData = new FormData();
formData.append(photo?.imageFileName, photo?.imageFile)
dispatch({ type: constants.UPLOAD_PHOTOS_START, size });
try {
const response = await axios.post(
`${API_URL}/photos/upload`,
formData,
{
onUploadProgress({ loaded, total }) {
dispatch(setUploadProgress({ id, loaded, total })); // Use id
},
signal: controller.signal,
}
);
dispatch({
type: constants.UPLOAD_PHOTOS_SUCCESS,
payload: response.data,
});
} catch (error) {
dispatch({
type: constants.UPLOAD_PHOTOS_FAILURE,
payload: error,
});
}
}
});
};