javascript - 使用 destroy() 和异步函数避免分配错误

标签 javascript gnome-shell gnome-shell-extensions gjs

以下是一些 GNOME 扩展的简单场景:

  1. 启用扩展。扩展是一个扩展的类 Clutter.Actor.
  2. 它创建了一个名为 myActor 的 actor 并添加了它: this.add_child(myActor).
  3. 然后它调用一个异步的 耗时的函数 this._tcFunction() 最后做了一些事情 使用 myActor

这是我遇到的问题:

  1. 我们在启用扩展后立即禁用(运行 this.destroy())。

  2. 禁用时,this.destroy() 运行 GObject 的 this.run_dispose() 以 收集垃圾。但是,如果 this._tcFunction() 还没有运行完, 稍后它会尝试访问可能已经存在的 myActorthis.run_dispose() 释放。

解决此问题的一种方法是在 this.destroy()

中定义一个 bool 变量
destroy() {
    this._destroying = true
    // ...
    this.run_dispose;
}

然后在this._tcFunction()中添加一个检查,例如

async _tcFunction() {
    await this._timeConsumingStuff();

    if (this._destroying === true) { return; }

    myActor.show();

}

我的问题:是否有更好的方法来处理这些情况?也许使用 Gio.Cancellable()? AFAIK,没有简单的方法来停止 javascript 中的异步函数...

最佳答案

首先要注意两点:

  1. 避免调用像 GObject.run_dispose() 这样的低级内存管理函数,因为在 C 库中有一些情况,这些对象被缓存以供重用,而不是实际上当你认为他们被处置时。也没有处置信号,其他对象可能需要通知。

  2. 避免覆盖触发处理的函数,例如 Clutter.Actor.destroy(),而是使用 destroy 信号。 GObject 信号回调始终将发射对象作为第一个参数,在销毁回调中使用that 是安全的。

我可以想到几种方法来解决这个问题,但这取决于具体情况。如果异步函数是 GNOME 库异步函数,它可能确实有一个可取消的参数:

let cancellable = new Gio.Cancellable();

let actor = new Clutter.Actor();
actor.connect('destroy', () => cancellable.cancel());

Gio.File.new_for_path('foo.txt').load_contents_async(cancellable, (file, res) => {
    try {
        let result = file.load_contents_finish(res);

        // This shouldn't be necessary if the operation succeeds (I think)
        if (!cancellable.is_cancelled())
            log(actor.width);
    } catch (e) {
        // We know it's not safe
        if (e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.CANCELLED))
            log('it was cancelled');

        // Probably safe, but let's check
        else if (!cancellable.is_cancelled())
            log(actor.width);
    }
});

// The above function will begin but not finish before the
// cancellable is triggered
actor.destroy();

当然,您始终可以使用带有 Promise 的可取消对象,或仅使用常规函数/回调模式:

new Promise((resolve, reject) => {
   // Some operation
   resolve();
}).then(result => {
    // Check the cancellable
    if (!cancellable.is_cancelled())
        log(actor.width);
});

另一种选择是null您的引用,因为您可以安全地检查它:

let actor = new Clutter.Actor();
actor.connect('destroy', () => {
    actor = null;
});

if (actor !== null)
    log(actor.width);

关于javascript - 使用 destroy() 和异步函数避免分配错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61401790/

相关文章:

javascript - React.js 告诉你取消 promise 。官方 promise 不能取消。我应该怎么做?

javascript - 在表单提交时保持选项卡打开 - 无需 Ajax

chromium - GNOME Shell 集成扩展正在运行,未检测到 native 主机连接器?

javascript - 设置为 gnome shell 扩展的模态

javascript - 在 CJS/GJS (Gnome JavaScript) 中开发 Cinnamon Shell 扩展 (Desklet) 的介绍?

JavaScript:调用原型(prototype)返回 'not a function' 错误

gnome - 如何处理 gnome shell 扩展中的键盘事件?

linux - 使用 CSS 使 Gnome 顶部栏字体粗细加粗?

gnome - 如何获取 gnome-shell-extension 中的进程列表?

javascript - 操作 mongodb 查询中的列表