इस क्रिया प्रकार को देखते हुए:

interface SaveFoo {
  type: 'SAVE_FOO'
  payload: {
    id: string
    value: number
  }
}

मैं एक ऐसी गाथा बनाना चाहता हूं जो चुनिंदा आधार पर हैंडलर को थ्रॉटल करे। तो उदाहरण के लिए यदि निम्नलिखित कार्रवाइयां भेजी गईं:

  1. { type: 'SAVE_FOO', payload: { id: "a", value: 1 } }
  2. { type: 'SAVE_FOO', payload: { id: "b", value: 1 } }
  3. { type: 'SAVE_FOO', payload: { id: "a", value: 2 } }
  4. { type: 'SAVE_FOO', payload: { id: "a", value: 3 } }

मैं 1 और 2 (चूंकि उनके पास अलग-अलग id गुण हैं) के लिए हैंडलर को बंद करना चाहता हूं, लेकिन 3 और 4 को बफर को 1 ने संसाधन पूर्ण कर लिया है।

ऐसा लगता है कि यह काफी सामान्य उपयोग का मामला होना चाहिए लेकिन मुझे कुछ भी संबंधित नहीं मिला। मैंने हाथ से लागू करने की कोशिश की है लेकिन मुझे लगता है कि एक बेहतर तरीका होना चाहिए:

  export function splitThrottle<T>(actionCreator: ActionCreator<T>, saga: (action: Action<T>) => SagaIterator, selector: (payload: T) => string) {
    const tasks: Record<string, Task> = {}
    const bufferLookup: Record<string, Buffer<Action<T>>> = {}

    function* queue(action: Action<T>, id: string) {
      try {
        yield call(saga, action)
      } catch (e) {
        // don't propagate
      }

      const next = bufferLookup[id].take()
      if (next) {
        tasks[id] = yield call(queue, next, id)
      } else {
        delete tasks[id]
      }
    }

    return function* () {
      while (true) {
        const action: Action<T> = yield take(actionCreator)
        const id = selector(action.payload)

        const existingTask = tasks[id]
        if (existingTask) {
          bufferLookup[id].put(action)
        } else {
          let buffer = bufferLookup[id]
          if (!buffer) {
            buffer = buffers.sliding(1)
            bufferLookup[id] = buffer
          }
          tasks[id] = yield fork(queue, action, id)
        }

      }
    }
  }
0
AlexFoxGill 26 नवम्बर 2018, 18:31

1 उत्तर

सबसे बढ़िया उत्तर

यहां बताया गया है कि मैंने इसे कैसे कार्यान्वित किया है। थोड़ा अलग आदिम के साथ बहुत ही समान समाधान:

export function* splitThrottle(pattern, saga, selector) {
  const channels = {}

  while (true) {
    const action = yield take(pattern)
    const id = selector(action)
    const { channel, justCreated } = obtainChannel(channels, id)

    yield put(channel, action)
    if (justCreated) {
      yield fork(processAllAndDelete, channels, id, saga)
    }
  }
}

function obtainChannel(channels, id) {
  let channel = channels[id]
  if (channel) {
    return { channel, justCreated: false }
  } else {
    channel = channels[id] = channel(buffers.expanding(1))
    return { channel, justCreated: true }
  }
}

function* processAllAndDelete(channels, id, saga) {
  const channel = channels[id]
  while (true) {
    const actions = yield flush(channel)
    if (!actions)
      break

    for (const action of actions) {
      yield call(saga, action)
    }
  }
  delete channels[id]
}
1
Andrey Moiseev 27 नवम्बर 2018, 00:47