點燈坊

失くすものさえない今が強くなるチャンスよ

如何判斷圖片 URL 是否存在 ?

Sam Xiao's Avatar 2021-07-20

若圖片 URL 不存在,會觸發 error event,可藉由此技巧判斷圖片 URL 是否存在。

Version

Vue 3.0.11

Promise

error000

若圖片 url 不存在,按下 Submit 會顯示 false

<template lang='pug'>
button(@click='onClick') Submit
div {{ result }}
</template>

<script setup>
import { ref } from 'vue'
import { write } from 'vue3-fp'
import { pipe, andThen as then, always as K } from 'ramda'

let result = ref ('')

let isImgUrlValid = url => new Promise (resolve => {
  let img = new Image
  img.onload = () => resolve (true)
  img.onerror = () => resolve (false)
  img.src = url
})

let onClick = pipe (
  K ('https://picsum.photo/300/200/?random=10'),
  isImgUrlValid,
  then (write (result))
)
</script>

第 9 行

let isImgUrlValid = url => new Promise (resolve => {
  let img = new Image
  img.onload = () => resolve (true)
  img.onerror = () => resolve (false)
  img.src = url
})

當傳入 圖片 url 存在時,會觸發 load event,否則會觸發 error event,因此可藉由 onloadonerror 回傳 truefalse

但問題來了,loaderror 為 event,屬於 asynchronous 行為,因此無法直接以 synchronous 回傳 truefalse,因此只能回傳 Promise,由於我們只希望回傳 truefalse ,因此只要回傳 Resolved 即可。

20 行

let onClick = pipe (
  K ('https://picsum.photo/300/200/?random=10'),
  isImgUrlValid,
  then (write (result))
)

由於 isImgUrlValid 回傳 Promise,因此只能使用 then 從 Promise 取出 value 寫入 result state。

Future

<template lang='pug'>
button(@click='onClick') Submit
div {{ result }}
</template>

<script setup>
import { ref } from 'vue'
import { write } from 'vue3-fp'
import S from 'sanctuary'
import { Future, value } from 'fluture'

let { unchecked: { pipe, K }} = S

let result = ref ('')

let isImgUrlValid = url => Future ((reject, resolve) => {
  let img = new Image
  img.onload = () => resolve (true)
  img.onerror = () => resolve (false)
  img.src = url
  return () => {}
})

let onClick = pipe ([
  K ('https://picsum.photo/300/200/?random=10'),
  isImgUrlValid,
  value (write (result))
])
</script>

16 行

let isImgUrlValid = url => Future ((reject, resolve) => {
  let img = new Image
  img.onload = () => resolve (true)
  img.onerror = () => resolve (false)
  img.src = url
  return () => {}
})

一樣使用 loaderror event 回傳 truefalse,但改回傳 Future。

24 行

let onClick = pipe ([
  K ('https://picsum.photo/300/200/?random=10'),
  isImgUrlValid,
  value (write (result))
])

由於 isImgUrlValid 回傳 Future,因此只能使用 value 從 Future 取出 value 寫入result state。

Conclusion

  • 若 function 想從 DOM event 回傳值,因為是 asynchronous 行為,因此只能回傳 Promise 或 Future