DEV Community

Cover image for Mastering AsyncSubject in RxJS: How to Emit the Final Value
vetriselvan Panneerselvam
vetriselvan Panneerselvam

Posted on

Mastering AsyncSubject in RxJS: How to Emit the Final Value

Hey Devs 👋

We’re back with another weekly RxJS exploration — and this time, we’re diving into an interesting and less commonly used concept: AsyncSubject.

🔍 What is an AsyncSubject?

Unlike other types of Subjects in RxJS, an AsyncSubject emits only the last value to its subscribers — and only when the subject completes.

Still confused? Don’t worry — let’s break it down step by step.

🧪 Basic Syntax

const subject = new AsyncSubject();
Enter fullscreen mode Exit fullscreen mode

🧰 Use Case Example in Angular

In this example, we'll bind a value from a textarea, send it to the AsyncSubject, and subscribe using the Angular async pipe.

🧩 HTML

<h3>AsyncSubject</h3>

<div class="text-wrapper">
  <div class="text">
    <textarea
      class="textarea-modern"
      [(ngModel)]="asyncSubjectText"
      name="asyncSubject"
      id="asyncSubject"
    ></textarea>
    <div class="btn-container">
      <button class="btn-ghost" (click)="sendAsyncSubject()">Send</button>
      <button class="btn-ghost" (click)="completeAsyncSubject()">Complete</button>
      <button class="btn-ghost" (click)="addAsyncSubject()">Add</button>
    </div>
  </div>

  <div class="example">
    <p>User Input:</p>
    @for (data of asyncSubjectData(); track $index) {
      <div class="card">
        <div class="index">{{$index}}</div>
        <div class="data">{{data | json}}</div>
      </div>
    }

    <p>AsyncSubject Value:</p>
    @for (item of asyncSubjectArray(); track $index) {
      @let data = asyncSubject | async;
      <div class="card">
        <div class="index">{{$index}}</div>
        <div class="data">{{data | json}}</div>
      </div>
    }
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

🧠 TypeScript

import { Component, model, OnInit, signal } from '@angular/core';
import { CommonModule } from '@angular/common';
import { AsyncSubject } from 'rxjs';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'app-rxjs-operator',
  imports: [CommonModule, FormsModule],
  templateUrl: './rxjs-operator.html',
  styleUrl: './rxjs-operator.scss',
})
export class RxjsOperator implements OnInit {
  asyncSubject = new AsyncSubject();
  asyncSubjectArray = signal<number[]>([0]);
  asyncSubjectText = model<string>('');
  asyncSubjectData = signal<string[]>([]);

  ngOnInit(): void {}

  addAsyncSubject() {
    this.asyncSubjectArray.update((prev) => [...prev, 1]);
  }

  sendAsyncSubject() {
    this.asyncSubjectData.update((prev) => [...prev, this.asyncSubjectText()]);
    this.asyncSubject.next(this.asyncSubjectText());
  }

  completeAsyncSubject() {
    this.asyncSubject.complete();
  }
}
Enter fullscreen mode Exit fullscreen mode

✅ Case 1: Initial State

Just like a regular Subject, AsyncSubject has no initial value. Before you send any data, subscribers receive null.

Image description

✅ Case 2: Sending Multiple Values

When sending multiple values through AsyncSubject, only the last value before calling .complete() is emitted to subscribers.

We print both the user’s input and what the AsyncSubject actually emits.

📌 Note: Once .complete() is called, no further values are accepted or emitted.

✅ Case 3: Multiple Subscribers

You can have multiple subscribers at different times. If the AsyncSubject is already completed, any new subscriber will immediately receive the last emitted value.

Image description

🧬 Under the Hood

Internally, AsyncSubject extends Subject, but overrides the next() and complete() methods.

export class AsyncSubject<T> extends Subject<T> {
  next(value: T): void {
    if (!this._closed) {
      this._value = value;
      this._hasValue = true;
    }
  }

  complete(): void {
    const { _hasValue, _value, _isComplete } = this;
    if (!_isComplete) {
      this._isComplete = true;
      _hasValue && super.next(_value!);
      super.complete();
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

When to Use AsyncSubject?

AsyncSubject is ideal when:

  • You need to emit only the final result after some operation is done.
  • You want to replicate Promise-like behavior using Observables.
  • You want subscribers to get only the final output, no matter when they subscribe.

🏁 Conclusion

AsyncSubject is powerful in scenarios where you care only about the final emitted value. Though used rarely, it’s an excellent fit for promise-style observables or final-state-only data sharing.

💬 Got questions or use cases you want to share? Drop a comment below! Let's discuss more Javascript magic. ✨

✍️ Author: Vetriselvan

👨‍💻 Frontend Developer | 💡 Code Enthusiast | 📚 Lifelong Learner | ✍️ Tech Blogger | 🌍 Freelance Developer

Top comments (0)