【问题标题】:Can you tell if an object is awaiting an async member function in TypeScript?你能判断一个对象是否正在等待 TypeScript 中的异步成员函数吗?
【发布时间】:2022-02-14 01:09:46
【问题描述】:

我正在使用 TypeScript 处理 Web 应用程序的客户端。

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

以下是该类的一些代码供参考(不是可执行示例):

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();
        }
    }

}

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

但是,当 ViewBinder 等待show 命令(在loadViewsetupAfterShowing 调用期间)时,底层客户端状态对象很少发生更改,这些更改会导致代码调用@987654328 @ 方法,删除父元素的主体,它应该插入它的 HTML 并绑定数据。

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

请注意,我已尝试使用 showWasCanceled 来避免此问题,但在派生的 setupAfterShowing 方法中存在太多潜在问题的情况,以确保在 showWasCanceled 设置为 @987654332 时我总是中止@。

所以,这是我的问题:

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

【问题讨论】:

    标签: typescript async-await


    【解决方案1】:

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

    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;
      ...
    }
    

    【讨论】:

    • 我对原始 Promises 的使用还不够多,无法将其识别为解决方案。因此,一旦创建了 Promise,该 Promise 上的任何 await 都将一直等待,直到 Promise 调用它的 resolve 或 reject 函数,对吗?我可能会将 promise 设为可选属性,并在 show 的开头创建它,这样如果 clear 方法未定义,我可以运行它,如果它已定义,我可以等待它。这样,如果在show 之前由于某种原因调用了clear,就没有问题。无法轻松测试它,因为我必须先让所有明确的呼叫都在等待,但它看起来是一个不错的答案。
    • 是的,这个 promise 是一个信号,所以 clear 方法必须等待它,然后才能继续执行其余的实际逻辑。
    【解决方案2】:

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

    但是,我最终采用了一种有点老派的方法,并想在此处记录它以防其他人发现它有用。

    请注意,这也使我不必将clear 设为async 方法(这导致我在很多地方都使用async“all-the-way-down”)。

    这里是描述:

    首先我在类中添加了两个布尔值: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...
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-04-08
      • 1970-01-01
      • 1970-01-01
      • 2019-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-07
      相关资源
      最近更新 更多