Reputation: 23
Ok, so I've just spent a day figuring out how to use callback-functions within sagas. (Please be nice, I'm just learning this saga-stuff)
My initial problem: I get an xml-response from the server and before going into my reducer I want to parse it into a js-object. Therefore I use xml2js.
Calling this xml2js library works with a callback:
parseString(xmlInput, (err, jsResult) => {
// here I'd like to put() my success-event, however that's not possible in this scope
})
After reading a lot about eventChannels, I've come up with this solution:
My Channel-Function:
function parseXMLAsyncronously (input) {
return eventChannel(emitter => {
parseString(input, (err, result) => {
emitter(result)
emitter(END)
})
return () => {
emitter(END)
}
})
}
Using it inside the saga:
const parsedJSObject = yield call(parseXMLAsyncronously, xmlFromServer)
const result = yield take(parsedJSObject)
The problem that I'm encountering now is that apparently even while using a callback-structure, the parseString-function is still executed synchronously. So when I get to my yield-line, the parsing has already been done and I can wait forever because nothing will happen anymore.
What's working is to make the parsing asynchronously, by replacing
parseString(input, (err, result) => {...}
with
const parser = new Parser({async: true})
parser.parseString(input, (err, result) => {...}
So basically I'm making an already blocking function unblocking just to block (yield) it again and then wait for it to finish.
My question is now pretty simple: Is there maybe a smarter way?
Upvotes: 0
Views: 288
Reputation: 4975
Why not just use the cps
effect?
try {
const result = yield cps(parseString, input)
} catch (err) {
// deal with error
}
Upvotes: 1