(node: ReactiveNode)
| 210 | * Called by implementations when a producer's signal is read. |
| 211 | */ |
| 212 | export function producerAccessed(node: ReactiveNode): void { |
| 213 | if (inNotificationPhase) { |
| 214 | throw new Error( |
| 215 | typeof ngDevMode !== 'undefined' && ngDevMode |
| 216 | ? `Assertion error: signal read during notification phase` |
| 217 | : '', |
| 218 | ); |
| 219 | } |
| 220 | |
| 221 | if (activeConsumer === null) { |
| 222 | // Accessed outside of a reactive context, so nothing to record. |
| 223 | return; |
| 224 | } |
| 225 | |
| 226 | activeConsumer.consumerOnSignalRead(node); |
| 227 | |
| 228 | const prevProducerLink = activeConsumer.producersTail; |
| 229 | |
| 230 | // If the last producer we accessed is the same as the current one, we can skip adding a new |
| 231 | // link |
| 232 | if (prevProducerLink !== undefined && prevProducerLink.producer === node) { |
| 233 | return; |
| 234 | } |
| 235 | |
| 236 | let nextProducerLink: ReactiveLink | undefined = undefined; |
| 237 | const isRecomputing = activeConsumer.recomputing; |
| 238 | if (isRecomputing) { |
| 239 | // If we're incrementally rebuilding the producers list, we want to check if the next producer |
| 240 | // in the list is the same as the one we're trying to add. |
| 241 | |
| 242 | // If the previous producer is defined, then the next producer is just the one that follows it. |
| 243 | // Otherwise, we should check the head of the producers list (the first node that we accessed the last time this consumer was run). |
| 244 | nextProducerLink = |
| 245 | prevProducerLink !== undefined ? prevProducerLink.nextProducer : activeConsumer.producers; |
| 246 | if (nextProducerLink !== undefined && nextProducerLink.producer === node) { |
| 247 | // If the next producer is the same as the one we're trying to add, we can just update the |
| 248 | // last read version, update the tail of the producers list of this rerun, and return. |
| 249 | activeConsumer.producersTail = nextProducerLink; |
| 250 | nextProducerLink.lastReadVersion = node.version; |
| 251 | nextProducerLink.knownValidAtEpoch = epoch; |
| 252 | return; |
| 253 | } |
| 254 | } |
| 255 | |
| 256 | const prevConsumerLink = node.consumersTail; |
| 257 | |
| 258 | // If the producer we're accessing already has a link to this consumer, we can skip adding a new |
| 259 | // link. This can short circuit the creation of a new link in the case where the consumer reads alternating ReactiveNodes |
| 260 | if ( |
| 261 | prevConsumerLink !== undefined && |
| 262 | prevConsumerLink.consumer === activeConsumer && |
| 263 | (!isRecomputing || prevConsumerLink.knownValidAtEpoch === epoch) |
| 264 | ) { |
| 265 | return; |
| 266 | } |
| 267 | |
| 268 | // If we got here, it means that we need to create a new link between the producer and the consumer. |
| 269 | const isLive = consumerIsLive(activeConsumer); |
no test coverage detected
searching dependent graphs…