你能判断 object 是否在等待 TypeScript 中的异步成员函数吗?

Can you tell if an object is awaiting an async member function in TypeScript?

我正在使用 TypeScript 开发 client-side 网络应用程序。

我有自己的“框架”,我开发了一个 class (ViewBinder),它使用异步“显示”方法从服务器加载信息,提取 HTML,然后插入它进入 parent “占位符”元素内的文档。然后,其派生的 classes 可以将来自客户端状态 object 的数据“绑定”到加载的 HTML.

这里是 class 中的一些代码供参考(不是可执行示例):

export class ViewBinder extends PropertyChangedNotifier {
    // Lots of member stuff not shown for brevity...

    public async show(callbackAfterShow?: (wasSuccessful: boolean) => void): Promise<HtmlLoadViewResult> {
        this.showWasCanceled = false;
        const loadResult = await this.loadView();
        if (this.showWasCanceled) {    // Helps my situation some but not fully
            // If this.clear() was called during loadView, we just move on...
            loadResult.wasCanceled = true;
        } else {
            // HERE is where I can have a problem: if this.clear() is called
            // while a derived class is doing its setupAfterShowing, the underlying
            // HTML will be removed and the attempt to setup (binding data to the
            // HTML) will cause an unwanted error.
            await this.setupAfterShowing(loadResult);
            // CODE REMOVED FOR BREVITY
        }
        return loadResult;
    }

    public clear(): void {
        // If the show function is awaiting anything, tell it it was canceled
        // BUT: what I WANT to do is somehow wait until show() is done before
        // continuing the execution of this function... see the question text
        this.showWasCanceled = true;
        this.localViewBinders.forEach((viewBinder) => viewBinder?.clear());
        this.localBindingContexts.forEach((context) => context?.clear());
        if (this.parentElement) {
            this.parentElement.innerHTML = "";
            if (this.isModalDialog) {
                this.parentElement.remove();
            } else {
                this.collapse();
            }
            this.parentElement = null;  // We are no longer associated with the element
            this.notifyPropertyChanged("visibility");
            this.removeAllPropertyChangedListeners();
        }
    }

}

请注意,派生的 classes 将开发 setupAfterShowing 方法,将来自客户端状态 object 的数据“绑定”到已加载的 HTML(并且可以调用 show 自己的“child”ViewBinders)。还有一个 clear 命令从 parent 元素中删除所有 HTML 并清除所有“数据绑定”。

但是,在 ViewBinder 等待 show 命令时(在 loadViewsetupAfterShowing 调用期间,底层客户端状态 object 发生变化的情况很少见,并且这些更改导致代码调用 clear 方法,删除应该插入 HTML 的 parent 元素的主体并绑定数据。

一般来说,如果 ViewBinder 找不到 parent 元素或无法在该元素中找到显示数据的位置,我认为这是一个错误并抛出错误。但是,在这种情况下,HTML 将在异步代码等待结果时“合法地”删除。

请注意,我已尝试使用 showWasCanceled 来避免此问题,但派生的 setupAfterShowing 方法中存在太多潜在问题,以确保我始终在 showWasCanceled 设置为 true.

所以,这是我的问题:

我的 clear 函数是否有办法确定 show 函数是否“正在等待”并暂停执行直到“显示”完成?

这样做的一种方法是创建一些字段来保存此类信息,例如

private promise;
private resolve;
private reject;

init() {
  this.promise = new Promise((res, rej)=>{
    this.resolve = res;
    this.reject= rej;
  });
}

public async show(...) {
  ...
  resolve(null); // or reject if any error thrown above
}

public async clear() {
  await this.promise;
  ...
}

我将接受@ABOS 的回答,因为它本着 async/await 流程的精神提供了一个解决方案(让 clear() 等待 show() 可以解决的承诺).

但是,我最终采取了某种 old-school 的方法,并想在此处记录下来以防其他人发现它有用。

请注意,这也使我不必制作 clear 一个 async 方法(这导致我在很多地方去 async “all-the-way-down” ).

描述如下:

首先,我向 class 添加了两个布尔值:clearWasCalledisRunningShow

调用show()时,它设置this.clearWasCalled = falsethis.isRunningShow = true。在 show() 的末尾,它设置 this.isRunningShow = false,如果 this.clearWasCalled === true,它将调用 this.clear()

clear()被调用时,它检查是否this.isRunningShow === true,如果是,它设置this.clearWasCalled = true并退出。

因此,在等待 show() 方法时,如果调用 clear(),它不会中断 show() 函数,而只是设置一个标志。 show() 完成后,它会检查标志是否已设置,如果已设置,它会确保 clear 操作已完成。

这里是代码中的基本思想:

export class ViewBinder extends PropertyChangedNotifier {
    // Lots of member stuff not shown for brevity...

    public clearWasCalled = false;
    public isRunningShow = false;

    public async show(callbackAfterShow?: (wasSuccessful: boolean) => void): Promise<HtmlLoadViewResult> {
        this.clearWasCalled = false;
        this.isRunningShow = true;
        const loadResult = await this.loadView();
        if (this.clearWasCalled === false) {    // Just in case...
            // If this.clear() was called during loadView, we just move on...
            loadResult.wasCanceled = true;
        } else {
            await this.setupAfterShowing(loadResult);
            // CODE REMOVED FOR BREVITY
        }
        this.isRunningShow = false;
        if (this.clearWasCalled) {
            this.clear();
            loadResult.wasCanceled = true;
        }
        return loadResult;
    }

    public clear(): void {
        // If we're running a show method, don't clear until it's done
        if (this.isRunningShow) {
            this.clearWasCalled = true;
            return;
        }

        // PERFORM CLEAR ACTIONS...
    }

}