angularangular-signals

Is it bad practice to call a computed signal from within a loop?


Is calling a computed signal within a loop bad practice?

Should I be avoiding this:

const filtered = computed(() => {
  return listItems.filter(item => item.name.includes(searchString())
});

and instead always do this:

const filtered = computed(() => {
  const search = searchString();
  return listItems.filter(item => item.name.includes(search)
});

I just did a quick performance test as follows:

const someComputation = computed(() => ...)
const before = performance.now();
for (let i = 0; i < 10000; i++)
  someComputation();
console.log(`Time taken: ${performance.now() - before}`)

This performs very well. The above code logs 5 (as in 5 milliseconds). As we know, Angular is caching previous results and not recomputing if none of the computed signals dependencies change.

Is calling a signal in a loop considered a code-smell? Is it bad practice and to be avoided out of principle?


Solution

  • Calling a computed signal within a loop is not inherently bad practice but it really depends on how the dependencies of the signal behave and how the loop interacts with them.

    you have to consider some things:

    given your example:

    const filtered = computed(() => {
      return listItems.filter(item => item.name.includes(searchString()));
    });
    

    the searchString() is a signal dependency here. As long as searchString() doesn't change, filtered() always returns the cached value. However every iteration might trigger the searchString() function call inside the filter loop, potentially causing unnecessary reads.

    so your alternative would definitely be the better practice in some cases:

    const filtered = computed(() => {
      const search = searchString(); // Read signal **once**
      return listItems.filter(item => item.name.includes(search));
    });
    

    Now, searchString() is called once per computation, avoiding multiple function calls inside the filter() which is more efficient when filter is run frequently or on larger datasets.

    so the best practice would be to extract signal values outside loops or performance-critical sections when possible.