Come Nirrek spiegato, quando si ha bisogno di connettersi a spingere le fonti di dati, si dovrà costruire un iteratore evento per quella fonte.
Vorrei aggiungere che il meccanismo di cui sopra potrebbe essere reso riutilizzabile. Quindi non dobbiamo ricreare un iteratore di eventi per ogni diversa fonte.
La soluzione è creare un canale generico con i metodi put
e take
. È possibile chiamare il metodo take
dall'interno del generatore e collegare il metodo put
all'interfaccia listener dell'origine dati.
Ecco una possibile implementazione. Si noti che il canale buffer messaggi se nessuno è in attesa per loro (per esempio il generatore è occupato a fare un po 'di chiamata remota)
function createChannel() {
const messageQueue = []
const resolveQueue = []
function put (msg) {
// anyone waiting for a message ?
if (resolveQueue.length) {
// deliver the message to the oldest one waiting (First In First Out)
const nextResolve = resolveQueue.shift()
nextResolve(msg)
} else {
// no one is waiting ? queue the event
messageQueue.push(msg)
}
}
// returns a Promise resolved with the next message
function take() {
// do we have queued messages ?
if (messageQueue.length) {
// deliver the oldest queued message
return Promise.resolve(messageQueue.shift())
} else {
// no queued messages ? queue the taker until a message arrives
return new Promise((resolve) => resolveQueue.push(resolve))
}
}
return {
take,
put
}
}
Poi il canale di cui sopra può essere utilizzato in qualsiasi momento si desidera ascoltare una sorgente di dati spinta esterna. Per il vostro esempio
function createChangeChannel (replication) {
const channel = createChannel()
// every change event will call put on the channel
replication.on('change', channel.put)
return channel
}
function * startReplication (getState) {
// Wait for the configuration to be set. This can happen multiple
// times during the life cycle, for example when the user wants to
// switch database/workspace.
while (yield take(DATABASE_SET_CONFIGURATION)) {
let state = getState()
let wrapper = state.database.wrapper
// Wait for a connection to work.
yield apply(wrapper, wrapper.connect)
// Trigger replication, and keep the promise.
let replication = wrapper.replicate()
if (replication) {
yield call(monitorChangeEvents, createChangeChannel(replication))
}
}
}
function * monitorChangeEvents (channel) {
while (true) {
const info = yield call(channel.take) // Blocks until the promise resolves
yield put(databaseActions.replicationChange(info))
}
}
fonte
2016-02-09 09:56:00
Che funziona perfettamente, grazie mille. Mi sono preso la libertà di aggiornare la tua risposta con il codice dalla mia app, quindi ora è testata, codice funzionante. – mikl
@ yassine-elouafi quali sono gli svantaggi di strappare il callback e trasformarlo in action creatore '(informazioni) => ({tipo: 'ON_CHANGE", info}) ', e guardare separatamente per' ON_CHANGE 'e fare' yield put (replicationChange (informazioni) 'lì? – biosckon