I'm creating a custom cycle.js driver with the purpose of preloading images. The main function exports a sink stream imagesToLoad emitting an array of image URLs. Those are then loaded by the driver and should return a stream that emits when the images are finished loading.
Problem
I can subscribe to the stream returned by the driver inside the driver's code and see that the loaded images are indeed emitted but never when mapping from inside the main function.
I am probably doing something wrong but I cannot see what exactly.
The driver
import { from, Subject } from 'rxjs'
import { adapt } from '@cycle/run/lib/adapt'
const loadImage = (src) =>
new Promise((resolve, reject) => {
const img = new Image()
img.addEventListener('load', () => resolve(img))
img.addEventListener('error', (err) => reject(err))
img.src = src
})
export const makeImageLoaderDriver = () => {
const imageLoaderDriver = (sink$) => {
const imageCache = {}
const source$ = new Subject()
from(source$).subscribe({
next(images) {
const imagesPromises = images.map((src) => {
const imgSuccess = { src, loaded: true }
if (!!imageCache[src]) return Promise.resolve(imgSuccess)
return loadImage(src)
.then(() => {
imageCache[src] = imgSuccess
})
.catch((error) => {
imageCache[src] = { src, loaded: false, error }
})
})
Promise.all(imagesPromises).then(() => {
source$.next(imageCache)
})
},
})
return adapt(source$)
}
return imageLoaderDriver
}
The index.js
const drivers = {
imagesToLoad: makeImageLoaderDriver(),
}
run(main, drivers)
The main function
export function main(sources) {
sources.imagesToLoad.pipe(map(console.log)) // THIS NEVER LOGS ANYTHING
return {
imagesToLoad: of([ imageUrl1, imageUrl2 ]),
}
}
sources.imagesToLoad.pipe(map(console.log))creates a new Observable, but this Observable is not named (as aconst) and is not used anywhere else. It's just dropped and never subscribed to, so effectively that line inmaindoes nothing.It needs to get plugged into one of the other stream pipelines that will some way end up in the sink. For instance, get the output of that operation, name it as a
const, and then use thatconststream in another stream pipeline, and this stream pipeline must eventually end up in a sink.To debug, you can put
.subscribe()after themap, and most likely you will see theconsole.loghappen. Just don't leave thesubscribe()in the code because Cycle.js is a framework where you don't ever need to subscribe on themainside, because subscriptions are meant for the drivers side.Notice also that your driver takes
sink$as input but it never uses that. You should subscribe tosink$and perform effects based on its emissions.