PunCha
PunCha

Reputation: 258

Different behavior to yield a promise between a plain generator and Redux saga

As I know, you can not get the promise by yield a promise in a generator. And the following test proves it is true. The ret is undefined:

function* foo() {
  const ret = yield Promise.resolve(50);
  console.log(`ret is ${ret}`);
}

const fooGen = foo();
fooGen.next();
fooGen.next()

But I cannot figure out why I can get the resolved promise value in Redux saga. See the following example (jsfiddle: https://jsfiddle.net/vymgr7de/1/)

// Sagas
function* saga() {
  yield call(function*() {
    const ret = yield Promise.resolve(50);
    yield put({type: "*", payload: `ret is ${ret}`});
  });
}

// => ret is 50

What trick does Redux saga play?

Upvotes: 2

Views: 154

Answers (1)

Martin Kadlec
Martin Kadlec

Reputation: 4975

To expand on my comment here is a code example that does something similar

function * test() {
    const result = yield new Promise(resolve => setTimeout(() => resolve('foo'), 1000))
    console.log('Result is: ', result)
}

function run(gen) {
    const iter = gen()
    const makeStep = (err, value) => {
        const step = !err ? iter.next(value) : iter.throw(err)
        if (step.done) return
        const p = step.value instanceof Promise ? step.value : Promise.resolve(step.value)
        p.then(val => makeStep(null, val), err => makeStep(err))
    }
    makeStep()
}

run(test)

As you can see, I am iterating over the generator and whenever I find a promise I wait until it is resolved and then pass the resolved value to iter.next(value), If I find anything else I convert it into resolved Promise so the yield expression instantly resolves to whatever it yielded.

Of course, redux-saga is not just looking for promises but also for all kinds of effects where each has its own defined functionality.

Upvotes: 3

Related Questions