如何使用vscode API编写异步代码(Promises?):withProgress

我很抱歉标题,我不知道如何更好地描述我的问题。

我想实现VSCode的withProgress API,以便在我的代码运行/进行时能够显示进度条。 文档在这里:https://code.visualstudio.com/api/extension-capabilities/common-capabilities#progress-api

我尝试实现它:

vscode.window.withProgress({
    location: vscode.ProgressLocation.Notification,title: "I am long running!",},(progress,token) => {
    return new Promise(resolve => {
        const output = executeProcess('sleep 5');
        resolve();
    });
});

executeProcess(...)是npm child_process.spawnSync的包装。我需要它是同步的,因为我想阅读它的标准输出。

所以,我的问题是它当前正在运行executeProcess,完成后便开始显示进度条。我如何编写它首先显示进度条,同时又在后台运行并完成其工作的方式?

是否有可能无需重组代码即可将child_process.spawn与回调一起使用?

Loewe2658 回答:如何使用vscode API编写异步代码(Promises?):withProgress

是的,我认为您必须更改代码以使用 async 模式,因为否则,您将阻塞要同时渲染进度对话框的UI线程。

这是使用spawnspawnSync之间的区别:

vscode.window.withProgress calling spawn vs spawnSync

如何在 async 方法中从子进程输出中读取示例:

        let childProcess = spawn(someProcessToSpawn)
            .on("close",(code,signal) => {
                console.log(`Closed: ${code} ${signal}`);
                if (childProcess.killed) { console.log('KILLED'); }
                resolve();
                clearInterval(interval);
            })
            .on("error",err => {
                reject(err);
            });

        childProcess.stdout
            .on("data",(chunk: string | Buffer) => {
                // YOUR CODE GOES HERE
                console.log(`stdout: ${chunk}`);
                progressUpdate = chunk.toString('utf8',50).replace(/[\r\n]/g,'');
            });

如果要运行整个示例,请克隆progress-sample,运行npm install并用以下代码替换 extension.ts 内容:

'use strict';

import { ExtensionContext,window,commands,ProgressLocation,CancellationToken,Progress } from 'vscode';
import { spawn,spawnSync } from 'child_process';

export function activate(context: ExtensionContext) {
    context.subscriptions.push(commands.registerCommand('extension.startTask',async () => {
        let mode = await window.showQuickPick(['sync','async'],{ placeHolder: 'Pick mode...' });
        window.withProgress({
            location: ProgressLocation.Notification,title: "I am long running",cancellable: true
        },async (progress,token) => {
            token.onCancellationRequested(() => {
                console.log("User canceled the long running operation");
            });

            switch (mode) {
                case undefined:
                    return; // canceled by the user
                case 'sync':
                    return spawnSomethingSync(token);
                case 'async':
                default:
                    return spawnSomethingAsync(progress,token);
            }
        });
    }));
}

/**
 * Synchronous approach
 * @param _token cancellation token (unused in the sync approach)
 */
function spawnSomethingSync(_token: CancellationToken): Promise<void> {
    return new Promise(resolve => {
        console.log('Started...');
        let child = spawnSync('cmd',['/c','dir','/S'],{ cwd: 'c:\\',encoding: 'utf8' });
        console.log(`stdout: ${child.stdout.slice(0,1000)}`); // otherwise it is too big for the console
        resolve();
    });
}

/**
 * Asynchronous approach
 * @param token cancellation token (triggered by the cancel button on the UI)
 */
function spawnSomethingAsync(progress: Progress<{ message?: string; increment?: number }>,token: CancellationToken): Promise<void> {
    return new Promise<void>((resolve,reject) => {
        if (token.isCancellationRequested) {
            return;
        }

        var progressUpdate = 'Starting up...';
        const interval = setInterval(() => progress.report({ message: progressUpdate }),500);

        let childProcess = spawn('cmd',{ cwd: 'c:\\' })
            .on("close",'');
            });

        token.onCancellationRequested(_ => childProcess.kill());
    });
}

如果您不在Windows上,只需用其他适当的长期运行命令替换dir /Sc:\\

使用 async 方法的另一个好处是,可以很容易地将“取消”按钮连接起来以杀死生成的进程:

token.onCancellationRequested(_ => childProcess.kill());

...,您还可以通过更新progress对象来显示进度。

本文链接:https://www.f2er.com/3139204.html

大家都在问