Tips on how to properly wait for Subject.next

Imagine having a subscription set up like this:

mySubject$.subscribe(async input => await complexFunction(input))

Assuming that mySubject$ is a Subject under your control. You require a method to achieve the following:

await mySubject$.next(input)

This allows you to wait for the completion of the complexFunction.

You attempted to devise a custom Subject implementation for this, but it proved to be challenging. Could there be a simpler solution that you are overlooking?

What other possibilities exist in this scenario?

Update:

In alignment with the principle that rxjs APIs should accept Promises, an attempt was made using the code below. Unfortunately, it was unsuccessful, leaving you at a loss once again.

function enhanceObservable<T>(observable: Observable<T>) {
    let resolve;
    return {
        waiter: new Promise<void>>(res => resolve = res),
        observable: observable.pipe(tap(() => resolve()))
    };
}

fdescribe('test', () => {
    it('should function correctly', async () => {
        const subject = new Subject<string>();
        const wrapper = enhanceObservable(subject);
        let testValue;
        wrapper.observable.subscribe(input => from(input).pipe(delay(1000), tap(value => testValue = value)).toPromise());
        subject.next('message');
        await wrapper.waiter;
        expect(testValue).toEqual('message');
    });
});

Answer №1

It seems like you're looking for a solution, and here's one that might suit your needs:

const data$ = mySubject$.pipe(
    mergeMap(input => processData(input))
);

data$.subscribe(
    result => console.log('Processed data:', result)
);

data$ is an observable that will output the processed data returned by processData() whenever mySubject$ triggers.

Answer №2

After much exploration, I have stumbled upon a resolution. While not overly simplistic, this solution is comprehendible. Note that the following code snippet is not a fully-fledged implementation; it requires additional cleanup and checks, but nonetheless, it does the job.

function awaitNext(testFunction) {
    return async function() {
        Subject.prototype['saved_subscribe'] = Subject.prototype.subscribe;
        Subject.prototype['saved_next'] = Subject.prototype.next;
        Subject.prototype['promiseArray'] = [];
        Subject.prototype['subscribe'] = function (n, e, c) {
            let wrappedN, wrappedE, wrappedC;
            wrappedN = v => {
                const p = n(v);
                if (p instanceof Promise) this.promiseArray.push(p);
            }
            wrappedE = v => {
                const p = e(v);
                if (p instanceof Promise) this.promiseArray.push(p);
            }
            wrappedC = v => {
                const p = c(v);
                if (p instanceof Promise) this.promiseArray.push(p);
            }
            return this.saved_subscribe(wrappedN, wrappedE, wrappedC);
        } as any;
        Subject.prototype['next'] = function (v) {
            this.saved_next(v);
            return Promise.all(this.promiseArray).then(() => this.promiseArray = []);
        }
        return await testFunction();
    }
}

Here is an example of how you can use this implemented solution:

it('works', awaitNext(async () => {
        const subject = new Subject<string>();
        let actualValue;
        subject.subscribe(v => of(v).pipe(delay(2000), tap(t => actualValue = t)).toPromise());
        await subject.next('foo');
        expect(actualValue).toEqual('foo');
}));

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Refresh the page without reloading to update the value of a dynamically created object

Maybe this question seems silly (but remember, there are no stupid questions).. but here it goes. Let me explain what I'm working on: 1) The user logs into a page and the first thing that happens is that a list of objects from a MySQL database is fet ...

Encountering a SyntaxError after deploying a Rails6 application: Unexpected token 'export' issue arises

After the most recent deployment, the application was functioning perfectly until it started displaying errors in Developer Tools and on every tab that is clicked within the application. The deployment process is carried out using Capistrano Uncaught Synt ...

"Struggling with solving an error in METEOR REACT SEARCH and DISPLAY upon user input onChange? Let

Here is the input code snippet: Title: <input type="text" ref="searchTitle" onChange={this.searchTitle}/> This function handles the onChange event: searchTitle(event) { this.setState({ show_article_editable_list: <Article_Editab ...

Update the div's class according to the video file it is linked to

Is it possible to dynamically show or hide a div depending on the source of a video being played? I have a slideshow of videos running using bigvideo.js and I am looking for a way to toggle the visibility of certain divs based on which video is currently ...

Collaborate with other components or services by exchanging observables

I'm encountering difficulties subscribing to an observer called from a different component. In my Angular 4 application, there is a navigation bar that displays user information. This information is fetched through an HTTP request to the server upon ...

How to turn off automatic formatting in CKEditor

Whenever data is entered into a field using CKEditor, the Save button becomes enabled. However, if I programmatically set data into the field using Javascript, the Change event always triggers causing the Save button to remain enabled even if the field is ...

Angular Protractor is hitting a limit with its executeScript and executeAsyncScript functions, throwing an error of "

Is it possible to access the isolated scope of a directive with Protractor using this code snippet? protractor.executeAsyncScript(function(callback){ var isoScope = angular.element("div[my-directive='data']").isolateScope(); callback(iso ...

Showing information through check boxes for selected criteria as they are ticked off

Currently, I am facing a challenge in displaying data from MySQL that contains multiple true(1) or false(0) values. I am looking for a solution to display them using checkboxes. My goal is to show results where the data will be true for multiple categories ...

Can jQuery be used to target pseudo elements such as scrollbars for selection?

Can you use jQuery to target pseudo elements like these: ::-webkit-scrollbar ::-webkit-scrollbar-track ::-webkit-scrollbar-thumb Is it possible to manipulate them through jQuery? #scroller { background: #fff; height: 300px; wid ...

Having difficulties accessing the /playlists route with express and app.get in my code

I am encountering a 404 status code error when trying to access app.get('/playlists'). The browser displays "cannot GET /playlists" and I can't seem to figure out why. Here is the code I am using: var express = require('express&apos ...

I'm having trouble understanding why I can't access the properties of a class within a function that has been passed to an Angular

Currently, I have integrated HTML 5 geolocation into an Angular component: ... export class AngularComponent { ... constructor(private db: DatabaseService) {} // this function is linked to an HTML button logCoords(message, ...

The error message "TypeError: jQuery(...).ready(...) is not a function" indicates that

Although this question has been asked before, none of the answers seem to solve my specific issue. I am attempting to run a small piece of jQuery code (as I am just starting to learn it). jQuery(document).ready(function(){ jQuery('.comtrig') ...

Conflicting node module versions arise during the installation of modules for electron

I'm currently developing an Electron application that interfaces with a serial port to read data. While I have experience with C++, I am relatively new to web technologies, although I do have some knowledge of JavaScript. After pulling the quick-star ...

My goal is to calculate a precise percentage for each text field and then determine the overall grade

<tr> <td>Knowledge</td> <td><input type="text" name="Knowledge" style="height: 30px; width: 220px;" class="computethis" id="knowledge" Placeholder = "Enter Grade" autocomplete ="off" /></td> </tr> <tr&g ...

How can I create a hover effect animation in React?

I am looking to replicate the menu item underline animation demonstrated in this example. In jQuery, I would easily achieve this by obtaining the left position and width of a menu item, then using stop.animation on hover. Attempting this animation with R ...

Utilizing Array in ReactJS with the Power of Hooks

My current situation involves having an array of FooBar objects interface FooBar { foo: string, bar: string, correct: string, other: string[] } const [arrOfObj, setArrOfObj] = useState<FooBar[]>([ { "foo": "fool ...

Determine the status of caps lock with a single click of a button

I am working on an application that includes a textbox and a button. I need the application to indicate whether the Caps Lock key is activated or deactivated when a user types text in the textbox and clicks the button. ...

Leverage the JSON data to populate the category axis in c3.js

I have a JSON object that contains an array called datas, which holds the data I need to use for my chart. I want to utilize the data1 array for the x-axis in a category format. How can I achieve this? This is my attempted solution, where I extract the da ...

Is there a way to utilize JavaScript to dynamically conceal elements on a webpage?

if (fbValue.job_requested) { var driver_id = fbValue.driver_id; var driver_name = fbValue.driver_name; var requested = fbValue.job_requested; var time = "00:00"; var list_id = "list"+driver_id; if (fbValue.j ...

I'm trying to figure out how to switch the Heroes array to the res array while utilizing the react useState hook. It's been successful in my past projects, but for some reason,

const [Heroes, setHeroes] = useState([]) useEffect(() => { API.findFavorites().then((res) => { console.log(res) setHeroes([...Heroes, res]); console.log(Heroes) }) }, []); I am struggling ...