LoginSignup
1

More than 3 years have passed since last update.

sagaで並列処理と逐次処理

Last updated at Posted at 2019-09-19

はじめに

ミリ秒間隔(もはや同時に叩かれるときもあり)で叩かれるactionのハンドリングをredux sagaでする必要があった。その時の試行錯誤の記録。

ver 1

はじめは普通にtakeで書いていたが、これだとactionを完全に拾えていなく、結構取り漏れている状況だった。


function* request(chan) {
  while (true) {
    const { payload } = yield take('REQUEST');

    // 'REQUEST'のactionが叩かれてはいるが、ここまで来ていないことが割とある
  }
}

ver 2

takeEveryを使い、並列に処理するようにしたら取り漏れることがなくなった。
それは良かったのだが、この _request の処理では各々の _request で共通して参照/更新したい値があった。しかし、 _request は並列で動いているため、単純に _request の処理内にその処理を書いても意味がない。
(仮に_requestがふたつ同時に並列で動いた場合、同時にその値を参照/更新してしまい値がバグる)

イメージとしてはgolangのchanみたいに各並列処理を取りまとめるキューみたいなのが欲しかった。


function* _request(action) {
  const { payload } = action;

  // some code
}

function* request() {
  yield takeEvery('REQUEST', _request);
}

ver 3

最終的にこうなった。
actionChannel を使えば、そのアクションをFIFOで処理するようなキューを作ってくれる。
ver 2で使っていた takeEvery だと、アクションのとり漏れは発生しないが並列処理になっちゃうので使わない。
このコードなら下記の // some code の部分は逐次処理されるようになっているので、 共通して使いたい値の参照/更新をそのまま書ける。

function* watchRequest() {
  const chan = yield actionChannel('REQUEST');

  while (true) {
    const { payload } = yield take(chan);

    // some code
  }
}

参考
https://qiita.com/r-nouchi/items/3809801b817e62b4f60b
https://stackoverflow.com/questions/58973428/how-to-take-multiple-actions-dispatched-with-blocking-call

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1