Waiting for multiple ipc calls to complete before continuing in electron/redux

I'm working on an app in Electron, React and Redux. At the program start, I'm making a few asynchronous ipc calls between the render process and the main process and save the results in the store.

// in the main app component
componentWillMount() {
    const { store } = this.context;
    store.dispatch(fetchOptions());
    store.dispatch(fetchRequirements());
    store.dispatch(fetchStats());
    /* miracle function */
},

// actions.js
export function fetchOptions() {
    return dispatch => {
        dispatch(requestOptions());
        ipcRenderer.on('sendOptions', function(event, arg) {
            dispatch(receiveOptions(arg));
        });
        ipcRenderer.send('requestOptions', '');
    };
}
// others accordingly

receiveOptions(arg), receiveRequirements(arg) and receiveStats(arg) are action creators and finally the reducer will save the responses in the store.

Directly after store.dispatch(fetchStats()), I want to dispatch another action to make some calculations based on the values that were loaded into the store. However, this action will usually be dispatched before the responses from ipc arrive.

I found this discussion with a similar problem, but they are making api calls with fetch instead of ipc messages, and I wouldn't know how to apply their idea to my problem.

So here is my question: how can I make the program wait for responses from all the channels before continuing?

Edit: When I set a time out of length 0 for the dispatches after the ipc calls, it works at least with immediate responses, but of course it doesn't help when the responses take a bit longer.

store.dispatch(fetchOptions());
store.dispatch(fetchRequirements());
store.dispatch(fetchStats());

setTimeout(function() {
    store.dispatch(calculateThis());
    store.dispatch(calculateThat());
}, 0);

Answers


An example using Promises
Assumption

I'm not familiar with how your icpRenderer works, or exaclty when the dispatching is completed. I am going to assume that the dispatch is completed after the call dispatch(receiveOptions(arg)) returns in

    ipcRenderer.on('sendOptions', function(event, arg) {
        dispatch(receiveOptions(arg));
    });

If dispatch() is asynchronous, this will not work (unless you wait to resolve the promise until after dispatch() is done).

If my assumption is correct

you should be able to return receive a "promise" (and resolve it) like this

    // actions.js
    export function fetchOptions(promise) {
        return dispatch => {
            dispatch(requestOptions());
            ipcRenderer.on('sendOptions', function(event, arg) {
                dispatch(receiveOptions(arg));
                if (promise) promise.resolve(); // Resolve the promise
            });
            ipcRenderer.send('requestOptions', '');
        }
    }
    // return Promises others accordingly

(Note that you may call fetchOptions without passing a "promise", because we only call promise.resolve() if promise is present. Hence, this should not complicate your existing code.)

In order to wait for the promises to resolve, you can do like this

    // in the main app component
    componentWillMount() {
        const { store } = this.context;
        const promises = [
            new Promise((resolve, reject) =>
                store.dispatch(fetchOptions({resolve, reject}))),
            new Promise((resolve, reject) =>
                store.dispatch(fetchRequirements({resolve, reject}))),
            new Promise((resolve, reject) =>
                store.dispatch(fetchStats({resolve, reject})))
        ];
        Promise.all(promises).then(() =>
            // Dispatch another action after the first three dispatches are completed.
        );
    },

The code didn't turn out super clean, but hopefully it will at least work.


Need Your Help

mod_rewrite - I can't make it to work like I want

php model-view-controller .htaccess apache2

Thanks for reading. First of all, I got one .htaccess inside my root directory with the following statement :