Home > Net >  How can I show Progress Notification with Promise Concurrency
How can I show Progress Notification with Promise Concurrency

Time:12-10

I am developing a VS Code Extension using TypeScript and need to make some concurrent child-process calls for each folder in the workspace, with a visible progress notification popup. Each new child process will likely take a few seconds to complete.

My approach seems to work fine from the perspective of the child_process calls but the progress bar disappears before all the commands have completed.

Here is a sample of the code I have been working with. Note that my understanding of using an async function with Array.map is that it will result in each await being ran concurrently. Hopefully I am correct with that.

export async function doStuffCmdHandler(channel: vscode.OutputChannel, context: vscode.ExtensionContext): Promise<void> {
    return vscode.window.withProgress({
            title: "Doing Stuff...",
            location: vscode.ProgressLocation.Notification,
        }, async (progress) => {
            if (vscode.workspace.workspaceFolders === undefined) {
                throw Error("Command must be ran from within a VS Code Workspace");
            } else {
                channel.clear();
                vscode.workspace.workspaceFolders.map(async (folder) => {
                    try {
                        // executeCommand() is a wrapper around child_process.exec which returns Promise<string>
                        let results = await executeCommand(folder.uri.path);
                        channel.show();
                        channel.append(results);
                    } catch (err) {
                        channel.show();
                        channel.append(`Error processing ${folder.uri.path}:\n\n`);
                        channel.append(`${(err as Error).message}\n\n`);
                    }
                });
            }
        }
    );
}

If I make my child process calls sequentially with a regular for loop (as per the snippet below) then I don't have any progress bar issues. Howevever, I would prefer to make these calls concurrently:

channel.clear();
for (var folder of vscode.workspace.workspaceFolders) {
    try {
        // executeCommand() is a wrapper around child_process.exec which returns Promise<string>
        let results = await executeCommand(folder.uri.path);
        channel.show();
        channel.append(results);
    } catch (err) {
        channel.show();
        channel.append(`Error processing ${folder.uri.path}:\n\n`);
        channel.append(`${(err as Error).message}\n\n`);
    }
};

CodePudding user response:

There is no use of progress anywhere in your code... Also you are not following the execution of the promises so your function ends before the promises end.

export async function doStuffCmdHandler(channel: vscode.OutputChannel, context: vscode.ExtensionContext): Promise<void> {
    return vscode.window.withProgress({
            title: "Doing Stuff...",
            location: vscode.ProgressLocation.Notification,
        }, async (progress) => {
            if (vscode.workspace.workspaceFolders === undefined) {
                throw Error("Command must be ran from within a VS Code Workspace");
            } else {
                channel.clear();
                const total = vscode.workspace.workspaceFolders.length;
                let done = 0;
   // Return a promise that will end once all promises have finished.
                return Promise.all(vscode.workspace.workspaceFolders.map(async (folder) => {
                    try {
                        // executeCommand() is a wrapper around child_process.exec which returns Promise<string>
                        let results = await executeCommand(folder.uri.path);
                        channel.show();
                        channel.append(results);
                        // Report something, reporting  done vs total
                        progress.report(  done "/" total);
                    } catch (err) {
                        channel.show();
                        channel.append(`Error processing ${folder.uri.path}:\n\n`);
                        channel.append(`${(err as Error).message}\n\n`);
                    }
                }));
            }
        }
    );
}
  • Related