How do I make ES6 generators wait for promises, li

2019-05-18 11:17发布

I've read that generators don't wait for promises. How come this is not the case with generators in redux-saga, and how do I make my own generators wait?

For example, this saga:

takeLatest('FETCH_USER_REQUESTED', function*() {
  const fetchPromise = yield put(fetchUser());
  const user = yield fetchPromise;
  console.log(user)
  yield 1
  console.log(1)
})

will output:

Promise
Object // <= user data fetched asynchronously
1

instead of:

Promise
undefined
1

1条回答
再贱就再见
2楼-- · 2019-05-18 11:55

How come this is not the case with generators in redux-saga, and how do I make my own generators wait?

This very popular belief, however generators in itself have no relation to Promises or asynchronous functions. Generators is just about make interruptible function with delegating some resources and responsibility to upper level function.

In case of redux-saga, there is two parts: independent saga runner process and scheduler (https://github.com/redux-saga/redux-saga/blob/master/src/internal/runSaga.js) , which is launched by sagaMiddleware.run() command, and effects reactions, which delegates actions into main saga process.

So, simplest process manager in ES6, which emulates redux-saga behavior, will be like that (very simplified):

const ProcessManager = (() => {
let context = new WeakMap();
function PM(rootSaga, lastValue) {
    if(!context.has(rootSaga)) {
        context.set(rootSaga, rootSaga())
    }
    const iterator = context.get(rootSaga);
    const { done, value } = iterator.next(lastValue);
    if(done) {
        context.delete(rootSaga)
        return;
    }
    if(Promise.resolve(value) === value) {
        value.then((asyncValue) => PM(rootSaga, asyncValue))
    } else {
        PM(rootSaga, value)
    }
}
return PM;
})()

const rootSaga = function* () {
    yield new Promise(resolve => setTimeout(resolve, 500));
    console.log('This will be printed after 500 ms from start');
    yield new Promise(resolve => setTimeout(resolve, 500));
    console.log('This will be printed after 1000 ms from start');
}

ProcessManager(rootSaga);
查看更多
登录 后发表回答