Is anyone able to point me to an example of preloading images with Compose-HTML?
Chris Miller
05/06/2023, 5:14 PM
I came up with this, which seems to do the trick:
Copy code
@Composable
fun ImgPreload(url: String, onLoaded: () -> Unit = {}) {
val signal = Semaphore(1, 1)
LaunchedEffect(url) {
val img = Image()
img.onload = {
signal.release()
}
// This will start the load
img.src = url
signal.acquire()
onLoaded()
}
}
a
Arjan van Wieringen
05/06/2023, 9:10 PM
Why use semaphores? It sounds to me this can easily be done with suspendCoroutine?
c
Chris Miller
05/07/2023, 10:14 AM
First time I've converted a callback to suspend function so I wasn't aware of it, thanks! Though that made me realise I'm effectively doing callback -> suspend -> callback which isn't needed. Also, seems like I'll have to hang on to the img reference so the browser doesn't GC/release the image again.
a
Arjan van Wieringen
05/07/2023, 11:07 AM
You could just attach them to a global window object, and let go of the reference. A bit dirty. Or, you create an image preloader which does that for you but still keeps the references.
c
Chris Miller
05/07/2023, 11:08 AM
Yep I've done the latter, just a circular array that holds the last 10 preloaded references. Should be plenty good enough for my purposes
Chris Miller
05/07/2023, 11:17 AM
For anyone interested:
Copy code
object Preloader {
// A cache of preloaded images. We never look in this cache, it's just here to prevent
// the browser from garbage collecting the most recent preloads.
private const val IMG_CACHE_SIZE = 10
private var imgCacheIndex = 0
private val imgCache = arrayOfNulls<Image>(IMG_CACHE_SIZE)
fun imgPreload(url: String, onLoaded: (Event) -> Unit = {}) {
val img = Image()
imgCache[imgCacheIndex] = img
imgCacheIndex = (imgCacheIndex + 1) % IMG_CACHE_SIZE
img.onload = { event ->
onLoaded(event)
}
// This will start the load
img.src = url
}
}