Should I mutate internal state of a value that was promised and is already resolved?

StackOverflow https://stackoverflow.com/questions/23359988

  •  11-07-2023
  •  | 
  •  

Pregunta

Code example (mutability)

.factory('objSingleton', function ($q) {
  var o = {a: 1}

  setTimeout(function () {
    o.a = 2
  }, 1000)

  return $q.when(o)
})

An alternative would be (immutability)

.factory('objFactory', function ($q) {
  var promise = $q.when({a: 1})

  setTimeout(function () {
    promise = $q.when({a: 2})
  }, 1000)

  return function () {
    return promise
  }
})

Question

I'd like to hear 'for's and 'against's to help me decide between embracing or refraining from treating the promises (in the APIs that create+return them) deeply immutable.

Note: Code example uses AngularJS style dependency injector, but the question and the answer is applicable to any and all JS environments that uses promises.

¿Fue útil?

Solución

Promises should not play any role in making this decision.

A promise, after all is just an abstraction over a calculation that might take time. The result of a promise, is an abstraction of a normal result.

Generally, it is good practice to have immutable values, as mutable state is really bad to have anyway. Mutable state makes testing harder. In your case, mutable global state is even worse. One of the finest articles on why is written by Angular's author Misko Havery and is called Singletons Are Pathological Liars.

So, the answer is - do what you would have done in synchronous code. Would you return a copy, or a reference in your synchronous code. This is a subjective question which I can't really answer, but all facts point to "have as little state as possible in your code".

Otros consejos

I highly disagree with your note. The framework plays a major role in this decision. In angular, if you attach the resolved value to one or several scopes and then mutate the resolved value then angular will update all relevant views for you automagically. I consider this to be a major feature of angular and so I do mutate my resolved promise values.

If you return a new promise you need to $watch the value yourself and take care of any updates to the view. Because of this, I would not prefer to use immutable values.

In other frameworks it might not work the same way and the question could have another answer.

Promise result values should definitely be considered immutable.

Promises do promote a functional programming style, and resolving them will settle their value forever. Their contract is that they will invoke all callbacks with the exactly same value, regardless of when this happens. You should not consider this only to be object identity, but also object "state".

Not mutating result values will lead to cleaner and less error-prone code. There are even promise libraries that enforce this by Object.freezeing the resolution value.

The only downside of such an approach is that the necessary cloning of the objects will be much slower. It is however acceptable to mutate the objects if you can be absolutely sure that nobody else but you consumes these values.

In my personal view, angular does take this far too liberally, but automatic propagation of such mutations is their design.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top