簡體   English   中英

檢測 ForEach() 循環內的最后一個實例 Promise — JavaScript

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM