【问题标题】:IndexedDB main thread & WebWorker eventlistenersIndexedDB 主线程和 WebWorker 事件监听器
【发布时间】:2016-01-14 02:51:00
【问题描述】:

您好,我正在构建一个使用 indexeDB 的应用程序。根据应用程序配置,我可以选择是否应该使用来自 WebWorker 或主 UI 线程的 indexeDB。无论配置如何,始终都会建立来自主 UI 线程的连接。但是,根据配置,如果选中,则工作人员正在完成繁重的工作。

导入原型示例:

Database.prototype.importItem = function(item, callback) {

    if (this.settings.useWorker) {

        this.postMessage({
            cmd: "importItem",
            data: item
        }, callback);

    } else {

        var that = this;
        var transaction = this.db.transaction(this.settings.collection, "readwrite");
        var objectStore = transaction.objectStore(this.settings.collection);
        var request = objectStore.add(item);

        request.onerror = function(evt) {
            if (callback && callback instanceof Function) {
                callback(new ApplicationError("importItem error", evt.target.error), null);
            }
        };

        request.onsuccess = function(evt) {
            if (callback && callback instanceof Function) {
                callback(null, evt.target.result);
            }
        };

        transaction.oncomplete = function(evt) {};

    }
};

我很好奇的想法是 indexedDB 所需的事件侦听器,例如:

Database.prototype.connect = function() {

    if (!this.supported()) {
        return this.emit("error", new ApplicationError("IndexedDB not supported!"));
    }

    var that = this;
    var openRequest = window.indexedDB.open(this.settings.dbName, this.settings.dbVersion);

    /**
     * [onerror description]
     * @param  {[type]} evt [description]
     * @return {[type]}     [description]
     */
    openRequest.onerror = function(evt) {
        that.emit("error", new ApplicationError("openRequest.onerror error", evt.target.error));
    };

    /**
     * [onblocked description]
     * @param  {[type]} evt [description]
     * @return {[type]}     [description]
     */
    openRequest.onblocked = function(evt) {
        // If some other tab is loaded with the database, then it needs to be closed
        // before we can proceed.
        alert("Please close all other tabs with this site open!");
    };

    /**
     * [onsuccess description]
     * @param  {[type]} evt [description]
     * @return {[type]}     [description]
     */
    openRequest.onsuccess = function(evt) {

        that.db = evt.target.result;

        that.db.onerror = function(evt) {
            logger.warn("openRequest.onsuccess error", evt.target);
        };

        that.db.onabort = function(evt) {
            logger.warn("openRequest.onsuccess abort", evt.target);
        };

        that.db.onversionchange = function(evt) {
            that.db.close();
            that.emit("versionchange", new ApplicationError("openRequest.onsuccess version change", evt.target));
        };

        if (that.settings.useWorker) {
            that.requestWorker();
        } else {
            that.emit("connect");
        }

    };

    /**
     * [onupgradeneeded description]
     * @param  {[type]} evt [description]
     * @return {[type]}     [description]
     */
    openRequest.onupgradeneeded = function(evt) {

        var stores = {};

        that.db = evt.target.result;

        that.db.onerror = function(evt) {
            logger.warn("openRequest.onupgradeneeded error", evt.target);
        };

        that.db.onabort = function(evt) {
            logger.warn("openRequest.onupgradeneeded abort", evt.target);
        };

        that.db.onversionchange = function(evt) {
            that.db.close();
            that.emit("versionchange", new ApplicationError("openRequest.onupgradeneeded version change", evt.target));
        };

        // Check for the objectStore - collection and delete it if exists
        if (that.db.objectStoreNames.contains(that.settings.collection)) {
            that.db.deleteObjectStore(that.settings.collection);
        }

        // Create new objectStore
        stores[that.settings.collection] = that.db.createObjectStore(that.settings.collection, {
            keyPath: that.settings.indexes[0]
        });

        // Create database indexes
        that.settings.indexes.forEach(function(index) {
            stores[that.settings.collection].createIndex(index, index, {
                unique: false
            });
        });

        that.upgraded = true;
        that.emit("upgrade");

    };

    /**
     * [onbeforeunload description]
     * @param  {[type]} evt [description]
     * @return {[type]}     [description]
     */
    window.onbeforeunload = function(evt) {
        that.db.close();
    };

};

由于我总是首先从主 ui 连接,然后从 worker 连接,我是否应该只在主 UI 线程而不是 worker 中监听诸如“onblocked, versionchange”之类的事件?我想这两个线程都不需要监听?

更新

我知道这是一个奇怪的实现,但我之所以考虑它是因为我正在一台具有 3GB 内存和 2 个内核的机器上构建一个应用程序......而且我有一个迭代所有我的数据库中的集合中的记录。我在想的是将检索到的每条记录传递给另一个用于图像加载和操作的方法,然后可能会调用回调......这将限制内存使用,因为如果我没记错的话,它将在一个系列中完成。但是我不确定交易是否仍然有效。

这是我考虑 2 个连接的主要原因(因为 1 个方法),我想知道是否可以避免双重事件侦听器。也许其中一些在 1 个线程上。

【问题讨论】:

  • 如果你总是只从一个线程使用 indexedDB,为什么还要从两个线程连接?
  • 因为有些方法不受网络工作者的支持。例如,我有一个方法可以迭代集合中的所有项目并将光标传递给执行画布绘制的回调,而网络工作者不支持画布
  • 是的,但是你不需要在主线程中建立 indexedDB 连接——你仍然可以在 Worker 中检索数据并将它们发送到主线程;然后在画布中绘制。您不需要从主线程和 Worker 进行连接。你描述的只是糟糕的设计,或者你描述的不对。
  • 是的,我想可以做到

标签: javascript indexeddb web-worker


【解决方案1】:

你做错了。不应在两个线程上打开 IndexedDB 连接。它使您的应用程序架构变得不必要地复杂。从 IndexedDB 检索的数据可以通过Web workers' messaging channel 与 UI 线程轻松交换。

【讨论】:

  • 是的,你是对的,我改变了我的实现。但是关于 onblocked 等事件仅在活动线程(工作线程或主线程)中被监控,并且消息正在发送给用户
  • @Syd 我不明白你的意思。你能澄清一下吗?为什么events onblocked etc 只在活动线程中被监控是个问题?
  • 事件在特定对象实例(例如请求、事务、连接)上触发,这些实例仅存在于工作程序或窗口上下文中且无法传输。因此,如果您在工作程序中打开连接,则无法从窗口监听事件,因为您没有任何东西可以附加事件监听器。
  • 好吧,假设您出于某种原因必须从工作人员和主线程建立 2 个连接。因为您无法直接从工作人员通知用户某些事件,例如警报等。 .您必须将事件传递回主用户界面。在那种情况下,为什么不从主 ui 监听这些事件并从那里处理工作人员关闭重新启动它等等......另外,我考虑使用 2 个连接的最初原因是因为我有一个方法可以迭代 a 中的所有项目集合,然后将光标传递给回调并在一些处理后调用它。
  • 在我的情况下,处理将是画布 - 图像处理。所以在那种特殊情况下,我不能将光标从工作线程传递给主线程......如果我错了,请纠正我。
猜你喜欢
  • 2014-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-06
  • 2020-11-29
  • 2019-12-02
  • 1970-01-01
  • 2023-03-14
相关资源
最近更新 更多