16

I want to introduce a delay in a saga (using redux-saga).

How can I do this?

If redux-saga provides an API, I would also be interested in how to achieve it manually.

function* save({ payload }) {
    yield put(pending());
    // I want to simply wait (non-blocking) here for say 2 seconds
    yield put(complete());
}
Ben Aston
  • 53,718
  • 65
  • 205
  • 331

4 Answers4

41

Redux-sagas has a special effect for this:

delay(ms, [val])

Returns a Promise that will resolve after ms milliseconds with val.

Example:

import { delay, call } from 'redux-saga/effects'

function* someSaga(input) {
  yield put(someAction())
  yield delay(500)
  yield put(anotherAction())
}
Cleiton
  • 17,663
  • 13
  • 46
  • 59
  • delay is in 'redux-saga/effects' not in redux-saga – Pasalino Apr 07 '19 at 13:14
  • @Pasalino that happened after version v1. Thank you to pointed out. I will update my answer. – Cleiton Apr 09 '19 at 18:22
  • 2
    instead of writing `yield call(delay, 5000)` where delay is an effect from `redux-saga/effects` you should write `yield delay(5000)` (quoting my console error :) ) – TecHunter Apr 29 '19 at 15:44
  • @TecHunter why we should use `yield delay(5000)` instead of `yield call(delay, 5000)`? Can you explain more specifically? – Leomord Jul 23 '20 at 00:54
3

You could achieve that with a promise and a generator function:

function sleep(sec) { 
    return new Promise(resolve => setTimeout(resolve, sec*1000)); 
}

function* save({ payload }) {
    yield put(pending());
    yield sleep(2); //wait 2 seconds
    yield put(complete());
}
NullDev
  • 6,739
  • 4
  • 30
  • 54
  • Would you need to `yield` the sleep promise? – Ben Aston Dec 04 '17 at 13:51
  • 1
    You need to do something - as written this will call `sleep` (returning a promise) and then immediately throw it away! If you yield a `call()` then redux-saga will wait for the promise to resolve, e.g.: `yield call(sleep, 2)`. The best solution is in the answer above - using the `delay` utility function. – simpleigh Mar 02 '18 at 14:08
0

Source.

export function delay(ms, val = true) {
  let timeoutId
  const promise = new Promise(resolve => {
    timeoutId = setTimeout(() => resolve(val), ms)
  })

  promise[CANCEL] = () => clearTimeout(timeoutId)

  return promise
}
Ben Aston
  • 53,718
  • 65
  • 205
  • 331
0

Using delay as imported from redux-saga/effects would solve your issue in one line