在 JS 中將非同步上傳與下載圖片改為同步

當網頁前端透過 fetch() 函數上傳一張圖片到後端,上傳完畢後再使用第二個 fetch() 將圖片抓回到前端顯示到 <img> 標籤上。這篇文章說明如何以極簡單的寫法讓這兩個非同步呼叫函數變成同步呼叫,畢竟圖片沒上傳完畢,前端也無法下載圖片來顯示,對吧?

首先,網頁內容如下。

<body>
    <form id="myform">
       <input type="file" name="file1"><p>
       <button id="button">click</button>
    </form>
    <p></p>
    <img id="image" width="240"></img>
</body>

網頁內容沒有什麼特殊的地方,簡單的一個表單裡面放一個檔案上傳標籤以及一個按鈕,表單外放一個之後要顯示圖片的標籤。接下來是 JavaScript 程式碼,如下。

window.onload = () => {
   button.onclick = async (event) => {
       const options = {
           method: 'post',
           body: new FormData(myform),
       } 

       event.preventDefault()
       let fileid = await (await fetch('upload.php', options)).text()
       image.src = await (await fetch(`showimage.php?fileid=${fileid}`)).text()
   }
}

這裡連續使用兩個 await 將 fetch() 本身的兩個非同步呼叫轉成同步呼叫,這樣一行就可以得到 fetch() 的傳回結果。如此一來,第一個 fetch() 用來上傳檔案到後端去存檔,第二個 fetch() 將後端存檔完畢的圖檔抓回到前端顯示。簡單兩行就可以將非同步呼叫改為同步呼叫,應該稱的上是超級簡單的寫法了。

PS: 連續兩個 await 在語法邏輯上而言一定可行,但最近手氣不好不知道哪裡打錯,課堂上居然沒有成功示範出來,變成明明一行可行的程式碼硬拆成兩行,程式碼就不好看了。

最後補上 upload.php 與 showimage.php 這兩隻後端程式,方便有興趣的人可以試試看。

<?php // upload.php
$src = $_FILES['file1']['tmp_name'];
$uniqid = uniqid();
$dst = "/Applications/XAMPP/xamppfiles/images/${uniqid}";
if (move_uploaded_file($src, $dst)) {
    print($uniqid);
} else {
    die($_FILES['file1']['error']);
}
<?php // showimage.php
$fileid = $_GET["fileid"];
$image = file_get_contents("/Applications/XAMPP/xamppfiles/images/${fileid}");
$mime_type = (new finfo(FILEINFO_MIME_TYPE))->buffer($image);
$base64 = base64_encode($image);
$src = "data:${mime_type};base64,${base64}";
print($src);

發表迴響