Skip to content

Commit

Permalink
feat: add poll effect type (#2158)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhanba authored and sorrycc committed Jul 12, 2019
1 parent 2b9f315 commit a5bdcd0
Show file tree
Hide file tree
Showing 4 changed files with 214 additions and 2 deletions.
1 change: 1 addition & 0 deletions docs/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ type includes:
* `takeLatest`
* `throttle`
* `watcher`
* `poll`

View https://github.com/dvajs/dva/blob/master/packages/dva-core/test/effects.test.js for details.

Expand Down
1 change: 1 addition & 0 deletions docs/api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,7 @@ type 类型有:
* `takeLatest`
* `throttle`
* `watcher`
* `poll`

详见:https://github.com/dvajs/dva/blob/master/packages/dva-core/test/effects.test.js

Expand Down
27 changes: 25 additions & 2 deletions packages/dva-core/src/getSaga.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ function getWatcher(key, _effect, model, onError, onEffect, opts) {
let effect = _effect;
let type = 'takeEvery';
let ms;
let delayMs;

if (Array.isArray(_effect)) {
[effect] = _effect;
Expand All @@ -33,10 +34,14 @@ function getWatcher(key, _effect, model, onError, onEffect, opts) {
invariant(opts.ms, 'app.start: opts.ms should be defined if type is throttle');
({ ms } = opts);
}
if (type === 'poll') {
invariant(opts.delay, 'app.start: opts.delay should be defined if type is poll');
({ delay: delayMs } = opts);
}
}
invariant(
['watcher', 'takeEvery', 'takeLatest', 'throttle'].indexOf(type) > -1,
'app.start: effect type should be takeEvery, takeLatest, throttle or watcher',
['watcher', 'takeEvery', 'takeLatest', 'throttle', 'poll'].indexOf(type) > -1,
'app.start: effect type should be takeEvery, takeLatest, throttle, poll or watcher',
);
}

Expand Down Expand Up @@ -74,6 +79,24 @@ function getWatcher(key, _effect, model, onError, onEffect, opts) {
return function*() {
yield sagaEffects.throttle(ms, key, sagaWithOnEffect);
};
case 'poll':
return function*() {
function delay(timeout) {
return new Promise(resolve => setTimeout(resolve, timeout));
}
function* pollSagaWorker(sagaEffects, action) {
const { call } = sagaEffects;
while (true) {
yield call(sagaWithOnEffect, action);
yield call(delay, delayMs);
}
}
const { call, take, race } = sagaEffects;
while (true) {
const action = yield take(`${key}-start`);
yield race([call(pollSagaWorker, sagaEffects, action), take(`${key}-stop`)]);
}
};
default:
return function*() {
yield sagaEffects.takeEvery(key, sagaWithOnEffect);
Expand Down
187 changes: 187 additions & 0 deletions packages/dva-core/test/effects.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,193 @@ describe('effects', () => {
}, 200);
});

it('type: poll', done => {
const app = create();
app.model({
namespace: 'count',
state: 0,
reducers: {
add(state, { payload }) {
return state + payload || 1;
},
},
effects: {
pollAdd: [
function*(_, { put }) {
yield put({ type: 'add', payload: 1 });
},
{ type: 'poll', delay: 1000 },
],
},
});
app.start();

app._store.dispatch({ type: 'count/pollAdd-start' });

setTimeout(() => {
app._store.dispatch({ type: 'count/pollAdd-stop' });
expect(app._store.getState().count).toEqual(2);
done();
}, 2000);
});

it('type: poll and stop', done => {
const app = create();
app.model({
namespace: 'count',
state: 0,
reducers: {
add(state, { payload }) {
return state + payload || 1;
},
},
effects: {
pollAdd: [
function*(_, { put }) {
yield put({ type: 'add', payload: 1 });
},
{ type: 'poll', delay: 1000 },
],
},
});
app.start();

app._store.dispatch({ type: 'count/pollAdd-start' });
// should work one time
app._store.dispatch({ type: 'count/pollAdd-stop' });

setTimeout(() => {
expect(app._store.getState().count).toEqual(1);
done();
}, 200);
});

it('type: poll with payload', done => {
const app = create();
app.model({
namespace: 'count',
state: 0,
reducers: {
add(state, { payload }) {
return state + payload || 1;
},
},
effects: {
pollAdd: [
function*({ payload }, { put }) {
yield put({ type: 'add', payload });
},
{ type: 'poll', delay: 1000 },
],
},
});
app.start();

app._store.dispatch({ type: 'count/pollAdd-start', payload: 2 });

setTimeout(() => {
app._store.dispatch({ type: 'count/pollAdd-stop' });
expect(app._store.getState().count).toEqual(4);
done();
}, 2000);
});

it('type: poll, start many time', done => {
const app = create();
app.model({
namespace: 'count',
state: 0,
reducers: {
add(state, { payload }) {
return state + payload || 1;
},
},
effects: {
pollAdd: [
function*({ payload }, { put }) {
yield put({ type: 'add', payload });
},
{ type: 'poll', delay: 1000 },
],
},
});
app.start();

app._store.dispatch({ type: 'count/pollAdd-start', payload: 2 });

setTimeout(() => {
// second start should not work
app._store.dispatch({ type: 'count/pollAdd-start', payload: 3 });
app._store.dispatch({ type: 'count/pollAdd-stop' });
expect(app._store.getState().count).toEqual(6);
done();
}, 3000);
});

it('type: poll, start many time 2', done => {
const app = create();
app.model({
namespace: 'count',
state: 0,
reducers: {
add(state, { payload }) {
return state + payload || 1;
},
},
effects: {
pollAdd: [
function*(_, { put }) {
yield put({ type: 'add', payload: 1 });
},
{ type: 'poll', delay: 1000 },
],
},
});
app.start();

app._store.dispatch({ type: 'count/pollAdd-start' });
// second start should not work
app._store.dispatch({ type: 'count/pollAdd-start' });

setTimeout(() => {
app._store.dispatch({ type: 'count/pollAdd-stop' });
expect(app._store.getState().count).toEqual(3);
done();
}, 3000);
});

it('type: poll, start and stop many time', done => {
const app = create();
app.model({
namespace: 'count',
state: 0,
reducers: {
add(state, { payload }) {
return state + payload || 1;
},
},
effects: {
pollAdd: [
function*(_, { put }) {
yield put({ type: 'add', payload: 1 });
},
{ type: 'poll', delay: 1000 },
],
},
});
app.start();

app._store.dispatch({ type: 'count/pollAdd-start' });
app._store.dispatch({ type: 'count/pollAdd-stop' });
app._store.dispatch({ type: 'count/pollAdd-start' });

setTimeout(() => {
app._store.dispatch({ type: 'count/pollAdd-stop' });
expect(app._store.getState().count).toEqual(3);
done();
}, 2000);
});

xit('nonvalid type', () => {
const app = create();
app.model({
Expand Down

0 comments on commit a5bdcd0

Please sign in to comment.