iT邦幫忙

0

javascript promise

  • 分享至 

  • xImage

我的 promise function 沒有正常運作, 請問是甚麼原因呢?

function getImages(imageArray){
	return new Promise((resolve, reject) => {
		let array = [1, 2, 3];
		for (let i = 0; i < imageArray.length; i++) {
		    const reader = new FileReader();
		    reader.onload = function (e) {
		    	const img = new Image();
		    	img.onload = function(){
		    		if(img.width === 960 && img.height === 960){
		    			let imgSrc = e.target.result.split(",");
		    			if(imgSrc[0].indexOf("png") > -1 || imgSrc[0].indexOf("jpg") > -1 || imgSrc[0].indexOf("jpeg") > -1){
		    				const imageHTML = [];
		    				imageHTML.push(`<input type='checkbox' class='imagecheckbox noM' id='imagecheckbox' onclick='checkit()' value="${i}">`);
		    				array.push(imageHTML);
		    			} else {
		    				alert("只允許上傳JPG、或PNG影像檔");return;
		    			}
		    		}else{
		    			alert("您所上傳圖片尺寸未符合規範");return;
		    		}	
		    	}
		    	img.src = e.target.result;
		    }
		    reader.readAsDataURL(imageArray[i]);			    
		}
		resolve(array);	
	});
    
	getImages($("#imageUpload")[0].files)
		.then((success) => {
			console.log(success);  // 這裡還是回傳空陣列
		})
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

0
淺水員
iT邦大師 6 級 ‧ 2023-05-04 19:25:33
最佳解答

提供參考,大致上是:

  1. 讀取檔案、讀取圖檔兩個步驟都是非同步,所以分別寫成兩個回傳 Promise 的函式方便串接
  2. 針對陣列中的每個元素都要代入非同步的狀況,可以用 Promise.all。或是改用 async...await 用迴圈去跑也可以。
function getImages(imageArray) {
    /**
     * 讀取檔案為 dataurl
     * @param {File} file 檔案
     * @returns {Promise.<string>} promise of dataurl
     */
    function readAsDataUrl(file) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onload = function (e) {
                resolve(e.target.result);
            }
            reader.readAsDataURL(file);
        });
    }

    function checkImage(dataurl) {
        return new Promise((resolve, reject) => {
            const img = new Image();
            img.onload = function () {
                if (img.width === 960 && img.height === 960) {
                    let imgSrc = dataurl.split(",");
                    if (imgSrc[0].indexOf("png") > -1 || imgSrc[0].indexOf("jpg") > -1 || imgSrc[0].indexOf("jpeg") > -1) {
                        resolve(dataurl);
                    } else {
                        reject("只允許上傳JPG、或PNG影像檔");
                    }
                } else {
                    reject("您所上傳圖片尺寸未符合規範");
                }
            }
            img.onerror = function () {
                reject("只允許上傳JPG、或PNG影像檔");
            }
            img.src = dataurl;
        });
    }
    return Promise.all(Array.from(imageArray).map(x => readAsDataUrl(x).then(checkImage)));
}

$("#imageUpload").on('change', evt => {
    getImages(evt.target.files)
        .then((success) => {
            console.log(success.map((dataurl, i) => {
                return `<input type='checkbox' class='imagecheckbox noM' id='imagecheckbox' onclick='checkit()' value="${i}">`;
            }));
        }).catch(error => {
            alert(error);
        });
});
看更多先前的回應...收起先前的回應...
hypons iT邦新手 5 級 ‧ 2023-05-04 20:47:25 檢舉

感謝,明天我會試一下~~

hypons iT邦新手 5 級 ‧ 2023-05-05 10:21:30 檢舉

淺水員成功了~~ 感謝.

所以原本的程式問題出在我把 讀取檔案、讀取圖檔 都寫在同一個promise裡面嗎?

淺水員 iT邦大師 6 級 ‧ 2023-05-05 11:14:01 檢舉

每個異步步驟包成一個 Promise 只是我習慣的做法
要寫成一個也是可以

你原先的問題主要是用迴圈處理 Promise 的部分
下面這寫法比較像你原本的,提供參考

async function getImages(imageArray) {
    let array = [];
    for (let i = 0; i < imageArray.length; i++) {
        let imageHTML = await new Promise((resolve, reject) => {
            const html = `<input type='checkbox' class='imagecheckbox noM' id='imagecheckbox' onclick='checkit()' value="${i}">`;
            const reader = new FileReader();
            reader.onload = function (e) {
                const img = new Image();
                img.onload = function () {
                    if (img.width === 960 && img.height === 960) {
                        let imgSrc = e.target.result.split(",");
                        if (imgSrc[0].indexOf("png") > -1 || imgSrc[0].indexOf("jpg") > -1 || imgSrc[0].indexOf("jpeg") > -1) {
                            resolve(html);
                        } else {
                            reject("只允許上傳JPG、或PNG影像檔");
                        }
                    } else {
                        reject("您所上傳圖片尺寸未符合規範");
                    }
                }
                img.onerror = function() {
                    reject("只允許上傳JPG、或PNG影像檔");
                }
                img.src = e.target.result;
            }
            reader.readAsDataURL(imageArray[i]);
        });
        array.push(imageHTML);
    };
    return array;
}

$("#imageUpload").on('change', evt => {
    getImages(evt.target.files)
        .then((success) => {
            console.log(success);
        }).catch(error => {
            alert(error);
        });
});
淺水員 iT邦大師 6 級 ‧ 2023-05-05 11:19:01 檢舉

昨天忘記說,上傳多張圖片時,imageHtml 的 id 會重複
這問題你再自己修一下吧

0

請善用 F12 大法。查看您的錯誤訊息。
而且 FileReader 元件是需要特定情況下使用的。
從你目前的程式碼來看,感覺並不是很正規的使用方式。

但因為還不太清楚您傳進來的imageArray值是什麼。
所以沒辦法判斷。

如果你傳進來的值是自已定義的檔案路徑。
那就一定是不能使用的。

其它詳細就請其它大大們補充

hypons iT邦新手 5 級 ‧ 2023-05-04 18:45:00 檢舉

他沒有錯誤訊息,
imageArray 的值是 <input id="imageUpload" type="file" draggable="true" accept="image/gif, image/jpeg, image/png" multiple="" onChange="selectImage()"> 的值

本來沒有promise, 是在每次for loop傳一次資料出去, 反而能成功....

我要發表回答

立即登入回答