[英]Detect The Last Instance Of A ForEach() Loop Inside A Promise — JavaScript
我有一些圖像文件作為文件上傳器的一部分進行預覽。 以及在后端 (PHP) 中發生的驗證我也在設置前端驗證。
當圖像附加到上傳者的文件<input>
元素時,使用URL.createObjectURL()
生成預覽縮略圖
這些預覽會循環播放,循環內的decode()
方法會檢測它們是否不符合某些條件。 如果失敗,則會輸出一條錯誤消息/附加到失敗的特定圖像文件(預覽縮略圖)。
如果檢測到此錯誤消息,則會在頁面頂部顯示一條通用錯誤消息,告訴用戶檢查圖像預覽縮略圖上顯示的錯誤。
問題
輸出頁面頂部的一般錯誤消息,但由於這一切都發生在循環內,如果附加了 5 個文件,並且只有一個失敗,則一般錯誤消息會閃爍,因為在循環的每個實例上都會檢測到它。
問題
如何檢測循環的最后一個實例,並且在最后一個循環實例發生時僅檢測 output 一般錯誤消息?
注意:我在下面包含了一個簡化的代碼示例,但很樂意展示完整的代碼(但我認為這對於這個問題來說可能有點矯枉過正)。
submitData = new DataTransfer();
// initial 'change' event listener on the files input element which is stored in a variable 'attachFiles'
attachFiles.addEventListener("change", (e) => {
// stuff here handles the data transfer method and detects any change in the number of files attached etc
// then run the 'showFiles function on each file attached
[...submitData.files].forEach(showFiles);
});
function showFiles(file) {
let previewImage = new Image();
// Set relevant <img> attributes
previewImage.className = "upload-preview-image";
previewImage.src = URL.createObjectURL(file);
// get the original width and height values of the thumbnail using the decode() method
previewImage.decode().then((response) => {
let w = previewImage.naturalWidth;
let h = previewImage.naturalHeight;
// error message that is appended to each image when it fails
let resError = `<p class="upload-preview-error">Image must be bigger than 2MP</p>`
if(w * h < 2000000) {
// append the above errorMessage to the specific image preview in question
previewImage.insertAdjacentHTML('beforebegin', resError);
}
// store HTML class from the above template string in a variable
let imgError = document.querySelectorAll('.upload-preview-error');
// set the variable that changes to true when an error message is detected
let imgErrorMessage = false;
/* SOMEHOW RUN THIS NEXT CODE ON THE LAST INSTANCE OF THE LOOP,
SO THAT THE MAIN ERROR MESSAGE AT THE TOP OF THE PAGE IS ONLY OUTPUTTED ONCE
*/
if(imgError.length) {
if (imgErrorMessage === false) {
// Append this generic message into a <div> with the class '.js-upload-error'
document.querySelector('.js-upload-error').innerHTML = `<p class="warning">YOU HAVE ERRORS. CHECK YOUR IMAGES BELOW</p>`
imgErrorMessage = true;
}
}
}).catch((encodingError) => {
// Do something with the error.
});
} // end of showfiles(file)
您看起來這里有一個虛擬錯誤處理塊:
}).catch((encodingError) => {
// Do something with the error.
});
當出現問題時,考慮在showFiles
中拋出一個錯誤,然后在調用者中使用Promise.allSettled
處理它以等待所有調用完成(完成或拒絕)。
從 UI 的角度來看,您幾乎肯定還想在出現其他錯誤時實際做一些事情來告訴用戶 - 換句話說,刪除empty // Do something with the error.
完全阻塞並讓調用者處理它。 (或者,如果您確實對該塊中的錯誤做了一些處理,您可以重新拋出它,以便調用者的.allSettled
可以看到存在問題。)
function showFiles(file) {
const previewImage = new Image();
previewImage.className = "upload-preview-image";
previewImage.src = URL.createObjectURL(file);
return previewImage.decode().then((response) => {
const w = previewImage.naturalWidth;
const h = previewImage.naturalHeight;
const resError = `<p class="upload-preview-error">Image must be bigger than 2MP</p>`
if (w * h < 2000000) {
previewImage.insertAdjacentHTML('beforebegin', resError);
throw new Error('Image too small');
}
});
}
並更換
[...submitData.files].forEach(showFiles);
和
Promise.allSettled([...submitData.files].map(showFiles))
.then((results) => {
if (results.some(result => result.status === 'rejected')) {
document.querySelector('.js-upload-error').innerHTML = `<p class="warning">YOU HAVE ERRORS. CHECK YOUR IMAGES BELOW</p>`;
// you can put more error handling here
// or you can put it in the .catch block if you re-throw
}
});
如果除了圖像太小之外還有其他錯誤,您可以在.catch
中添加這樣的錯誤消息,例如:
return previewImage.decode().then((response) => {
// ...
})
.catch((error) => {
if (error.message !== 'Image too small') {
previewImage.insertAdjacentHTML('beforebegin', '<p class="upload-preview-error">Decoding error</p>');
}
throw error;
});
或者使用.then(success, fail)
語法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.