RxJS: iif is not the same as defer with ternary operator

Wojciech Trawiński
JavaScript everyday
3 min readAug 9, 2019

Some time age I was introduced to the iif function from the RxJS library, which I’ve been always perceiving as a sort of syntactical sugar, namely that you can achieve everything it offers using already known RxJS functions. In addition, the official docs claims something similar:

If you have more complex logic that requires decision between more than two Observables, defer will probably be a better choice. Actually iif can be easily implemented with defer and exists only for convenience and readability reasons.

Although, the iif function undoubtedly improves readability and makes your code more declarative, there is a small gotcha, which I will cover in this blog post, that you should be aware of.

Inner observable

If you want to conditionally return a given stream from within a higher-order operator, e.g. the mergeMap, you can accomplish it in the following way:

Since the arguments of the ternary operator are evaluated in a lazy manner, each news producer is called once only.

You may consider the above example as a perfect place to use the iif function:

However, the iif function’s second and third arguments are eagerly evaluated, therefore both news producers are invoked for each news query. That’s the fact that you definitely should be aware of. The expressions responsible for providing observables for each scenario (truthy/falsy result of the predicate function) are evaluated immediately.

As an alternative, you can make use of the defer function in order to delay the moment of expressions evaluation:

However, in the above example it brings no benefit over the first solution with the raw ternary operator.

Dynamic observable

The need for using either the iif or the defer functions becomes more apparent when there is no source stream to create a resulting conditional observable:

In the above example, the resulting secretData$ stream should be determined based on the class field’s value which may dynamically change. Note that the fetch method is invoked before subscribing to the exposed observable.

The functionality provided by the iif function can be implemented with the aid of the defer function:

However, the callback function passed to the defer function is invoked for each observer at the moment of subscription.

Conclusions

Although the iif function may be simply implemented with the aid of the defer function, there are some important differences in behavior. In the former case, arguments, including expressions providing observables, are evaluated eagerly, whereas in the latter case, the callback function is invoked for each observer upon subscription. As a result, a new lexical scope is created for each observer and the streams-related expressions are evaluated in a lazy way. The more I’m familiar with the RxJS library, the more powerful the defer function seems to me.

Live example:

I hope you liked the post and learned something new 👍. If so, please give me some applause 👏

--

--