Skip to content

Commit a5bdcd0

Browse files
zhanbasorrycc
authored andcommitted
feat: add poll effect type (#2158)
1 parent 2b9f315 commit a5bdcd0

File tree

4 files changed

+214
-2
lines changed

4 files changed

+214
-2
lines changed

docs/API.md

+1
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,7 @@ type includes:
343343
* `takeLatest`
344344
* `throttle`
345345
* `watcher`
346+
* `poll`
346347

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

docs/api/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ type 类型有:
339339
* `takeLatest`
340340
* `throttle`
341341
* `watcher`
342+
* `poll`
342343

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

packages/dva-core/src/getSaga.js

+25-2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ function getWatcher(key, _effect, model, onError, onEffect, opts) {
2323
let effect = _effect;
2424
let type = 'takeEvery';
2525
let ms;
26+
let delayMs;
2627

2728
if (Array.isArray(_effect)) {
2829
[effect] = _effect;
@@ -33,10 +34,14 @@ function getWatcher(key, _effect, model, onError, onEffect, opts) {
3334
invariant(opts.ms, 'app.start: opts.ms should be defined if type is throttle');
3435
({ ms } = opts);
3536
}
37+
if (type === 'poll') {
38+
invariant(opts.delay, 'app.start: opts.delay should be defined if type is poll');
39+
({ delay: delayMs } = opts);
40+
}
3641
}
3742
invariant(
38-
['watcher', 'takeEvery', 'takeLatest', 'throttle'].indexOf(type) > -1,
39-
'app.start: effect type should be takeEvery, takeLatest, throttle or watcher',
43+
['watcher', 'takeEvery', 'takeLatest', 'throttle', 'poll'].indexOf(type) > -1,
44+
'app.start: effect type should be takeEvery, takeLatest, throttle, poll or watcher',
4045
);
4146
}
4247

@@ -74,6 +79,24 @@ function getWatcher(key, _effect, model, onError, onEffect, opts) {
7479
return function*() {
7580
yield sagaEffects.throttle(ms, key, sagaWithOnEffect);
7681
};
82+
case 'poll':
83+
return function*() {
84+
function delay(timeout) {
85+
return new Promise(resolve => setTimeout(resolve, timeout));
86+
}
87+
function* pollSagaWorker(sagaEffects, action) {
88+
const { call } = sagaEffects;
89+
while (true) {
90+
yield call(sagaWithOnEffect, action);
91+
yield call(delay, delayMs);
92+
}
93+
}
94+
const { call, take, race } = sagaEffects;
95+
while (true) {
96+
const action = yield take(`${key}-start`);
97+
yield race([call(pollSagaWorker, sagaEffects, action), take(`${key}-stop`)]);
98+
}
99+
};
77100
default:
78101
return function*() {
79102
yield sagaEffects.takeEvery(key, sagaWithOnEffect);

packages/dva-core/test/effects.test.js

+187
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,193 @@ describe('effects', () => {
414414
}, 200);
415415
});
416416

417+
it('type: poll', done => {
418+
const app = create();
419+
app.model({
420+
namespace: 'count',
421+
state: 0,
422+
reducers: {
423+
add(state, { payload }) {
424+
return state + payload || 1;
425+
},
426+
},
427+
effects: {
428+
pollAdd: [
429+
function*(_, { put }) {
430+
yield put({ type: 'add', payload: 1 });
431+
},
432+
{ type: 'poll', delay: 1000 },
433+
],
434+
},
435+
});
436+
app.start();
437+
438+
app._store.dispatch({ type: 'count/pollAdd-start' });
439+
440+
setTimeout(() => {
441+
app._store.dispatch({ type: 'count/pollAdd-stop' });
442+
expect(app._store.getState().count).toEqual(2);
443+
done();
444+
}, 2000);
445+
});
446+
447+
it('type: poll and stop', done => {
448+
const app = create();
449+
app.model({
450+
namespace: 'count',
451+
state: 0,
452+
reducers: {
453+
add(state, { payload }) {
454+
return state + payload || 1;
455+
},
456+
},
457+
effects: {
458+
pollAdd: [
459+
function*(_, { put }) {
460+
yield put({ type: 'add', payload: 1 });
461+
},
462+
{ type: 'poll', delay: 1000 },
463+
],
464+
},
465+
});
466+
app.start();
467+
468+
app._store.dispatch({ type: 'count/pollAdd-start' });
469+
// should work one time
470+
app._store.dispatch({ type: 'count/pollAdd-stop' });
471+
472+
setTimeout(() => {
473+
expect(app._store.getState().count).toEqual(1);
474+
done();
475+
}, 200);
476+
});
477+
478+
it('type: poll with payload', done => {
479+
const app = create();
480+
app.model({
481+
namespace: 'count',
482+
state: 0,
483+
reducers: {
484+
add(state, { payload }) {
485+
return state + payload || 1;
486+
},
487+
},
488+
effects: {
489+
pollAdd: [
490+
function*({ payload }, { put }) {
491+
yield put({ type: 'add', payload });
492+
},
493+
{ type: 'poll', delay: 1000 },
494+
],
495+
},
496+
});
497+
app.start();
498+
499+
app._store.dispatch({ type: 'count/pollAdd-start', payload: 2 });
500+
501+
setTimeout(() => {
502+
app._store.dispatch({ type: 'count/pollAdd-stop' });
503+
expect(app._store.getState().count).toEqual(4);
504+
done();
505+
}, 2000);
506+
});
507+
508+
it('type: poll, start many time', done => {
509+
const app = create();
510+
app.model({
511+
namespace: 'count',
512+
state: 0,
513+
reducers: {
514+
add(state, { payload }) {
515+
return state + payload || 1;
516+
},
517+
},
518+
effects: {
519+
pollAdd: [
520+
function*({ payload }, { put }) {
521+
yield put({ type: 'add', payload });
522+
},
523+
{ type: 'poll', delay: 1000 },
524+
],
525+
},
526+
});
527+
app.start();
528+
529+
app._store.dispatch({ type: 'count/pollAdd-start', payload: 2 });
530+
531+
setTimeout(() => {
532+
// second start should not work
533+
app._store.dispatch({ type: 'count/pollAdd-start', payload: 3 });
534+
app._store.dispatch({ type: 'count/pollAdd-stop' });
535+
expect(app._store.getState().count).toEqual(6);
536+
done();
537+
}, 3000);
538+
});
539+
540+
it('type: poll, start many time 2', done => {
541+
const app = create();
542+
app.model({
543+
namespace: 'count',
544+
state: 0,
545+
reducers: {
546+
add(state, { payload }) {
547+
return state + payload || 1;
548+
},
549+
},
550+
effects: {
551+
pollAdd: [
552+
function*(_, { put }) {
553+
yield put({ type: 'add', payload: 1 });
554+
},
555+
{ type: 'poll', delay: 1000 },
556+
],
557+
},
558+
});
559+
app.start();
560+
561+
app._store.dispatch({ type: 'count/pollAdd-start' });
562+
// second start should not work
563+
app._store.dispatch({ type: 'count/pollAdd-start' });
564+
565+
setTimeout(() => {
566+
app._store.dispatch({ type: 'count/pollAdd-stop' });
567+
expect(app._store.getState().count).toEqual(3);
568+
done();
569+
}, 3000);
570+
});
571+
572+
it('type: poll, start and stop many time', done => {
573+
const app = create();
574+
app.model({
575+
namespace: 'count',
576+
state: 0,
577+
reducers: {
578+
add(state, { payload }) {
579+
return state + payload || 1;
580+
},
581+
},
582+
effects: {
583+
pollAdd: [
584+
function*(_, { put }) {
585+
yield put({ type: 'add', payload: 1 });
586+
},
587+
{ type: 'poll', delay: 1000 },
588+
],
589+
},
590+
});
591+
app.start();
592+
593+
app._store.dispatch({ type: 'count/pollAdd-start' });
594+
app._store.dispatch({ type: 'count/pollAdd-stop' });
595+
app._store.dispatch({ type: 'count/pollAdd-start' });
596+
597+
setTimeout(() => {
598+
app._store.dispatch({ type: 'count/pollAdd-stop' });
599+
expect(app._store.getState().count).toEqual(3);
600+
done();
601+
}, 2000);
602+
});
603+
417604
xit('nonvalid type', () => {
418605
const app = create();
419606
app.model({

0 commit comments

Comments
 (0)