【问题标题】:Async changes in Dexie updating hookDexie 更新钩子中的异步更改
【发布时间】:2017-04-05 16:45:56
【问题描述】:

我正在尝试找出在存储或更改对象时使用钩子向对象添加一些字段的最佳方法。

基本思想是entry 对象必须包含一堆属性,这些属性基于一些复杂的查询和其他条目的计算。这些计算出的属性都存储在名为derived 的属性下。每次需要计算entry.derived 或从数据库中读取它时,计算它的成本会非常高。相反,我选择提前填充 derived 属性,而钩子似乎是这样做的最佳位置。

这对于creating 钩子来说似乎没有问题。但是,如果entry 中的任何其他属性发生更改,我还需要重新生成derivedupdating 钩子要求我通过返回它们来提交额外的更改,这是有问题的,因为我可以生成更改的唯一方法是通过异步调用。

下面是一些试图演示问题的最小代码。我还没有尝试过选项B,但我怀疑它也不起作用。

const entryDerivedData = function(entry) {
    // query a bunch of data from entries table then do some calculations
    return db.entries.where('exerciseID').equals(entry.exerciseID).toArray()
        .then(e => {
            // do some calculation and return
            return calculateDerivedData(e);
        });
};

// A: Can't do this because `hook` isn't expecting a generator func
db.entries.hook('updating', function*(mods, primKey, entry, transaction) {
    const derived = yield entryDerivedData(entry);
    return derived;
});

// B: Another possibility, but probably won't work either
db.entries.hook('updating', function(mods, primKey, entry, transaction) {
    transaction.scopeFunc = function() {
        return entryDerivedData(entry)
            .then(derived => {
                // Won't this result in another invocation of the updating hook?
                return db.entries.update(entry.id, {derived});
            });
    };
});

【问题讨论】:

    标签: dexie


    【解决方案1】:

    不幸的是,钩子是同步的,无法在其中进行异步调用。这是会改变的,但我不能保证什么时候发生。希望在未来 6 个月左右重写钩子框架,并允许批量钩子(性能更高)可以是异步的(保持现有钩子的向后兼容性)。

    在此之前,您可以利用钩子始终在事务中调用的事实(无论用户是否执行显式事务),并且您可以对当前事务执行其他操作。只需要确保您不会陷入无限循环,因为您的其他更改可能会再次触发您的钩子。

    一个例子是这样的:

    db.entries.hook('creating', (primKey, entry, trans) => {
      entryDerivedData(entry).then(derived => {
            db.entries.update(primKey, { derived }).catch (e => {
               // Failed to update. Abort transaction by rethrow error:
               throw new Error ("Could not make sure derived property was set properly");
            });
        });
    });
    
    db.entries.hook('updating', (mods, primKey, entry, trans) => {
        if ('derived' in mods) return; // We're the one triggering this change. Ignore.
        // First, apply the mods onto entry:
        var entryClone = Dexie.deepClone(entry);
        Object.keys(mods).forEach(keyPath => {
            if (mods[keyPath] === undefined)
                Dexie.delByKeyPath(entryClone, keyPath);
            else
                Dexie.setByKeyPath(entryClone, keyPath, mods[keyPath]);
        });
    
        entryDerivedData(entryClone).then(derived => {
            db.entries.update(primKey, { derived }).catch (e => {
               // Failed to update. Abort transaction by rethrow error:
               throw new Error ("Could not make sure derived property was set properly");
            });
        });
    });
    

    【讨论】:

      猜你喜欢
      • 2019-12-21
      • 1970-01-01
      • 2017-10-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-20
      • 2020-02-01
      • 2022-06-17
      • 1970-01-01
      相关资源
      最近更新 更多