使用 ES6 Proxy 延迟加载资源

Using ES6 Proxy to lazily load resources

我正在为存储在 MongoDB 中的文档构建类似 ActiveRecord class 的东西(类似于 Mongoose)。我有两个目标:

  1. 使用代理拦截文档上的所有 属性 setter,并自动创建更新查询发送到 Mongo。我已经在 SO 上找到了这个问题的

  2. 防止不必要的数据库读取。 IE。如果一个函数在文档上执行,并且该函数只 sets 属性,并且永远不会使用文档的现有 属性,那么我不需要从数据库中读取文档,我可以直接更新它。但是,如果该函数使用文档的任何属性,我必须先从数据库中读取它,然后才能继续编写代码。示例:

    // Don't load the document yet, wait for a property 'read'.
    const order = new Order({ id: '123abc' });
    // Set property.
    order.destination = 'USA'; 
    // No property 'read', Order class can just directly send a update query to Mongo ({ $set: { destination: 'USA' } }).      
    await order.save();                            
    
    // Don't load the document yet, wait for a property 'read'.
    const order = new Order({ id: '123abc' });
    // Read 'weight' from the order object/document and then set 'shipmentCost'.
    // Now that a 'get' operation is performed, Proxy needs to step in and load the document '123abc' from Mongo.
    // 'weight' will be read from the newly-loaded document.
    order.shipmentCost = order.weight * 4.5;     
    await order.save();     
    

我该怎么做?这看起来很简单:在文档对象上设置一个 'get' 陷阱。如果它是第一个 属性 'get',请从 Mongo 加载文档并缓存它。但是如何将异步操作放入 getter?

算术不能异步

您可能可以从 getter 中启动异步读取(我没有尝试过,但它似乎是合法的),但是 getter 等不及结果了。因此,除非您的数据库库提供一些 阻塞 访问调用,否则这一行,其中 order.weight 被及时获取并且乘法中使用的值,在 any 惰性读取机制:

order.shipmentCost = order.weight * 4.5

(如果你的数据库库确实有阻塞读取,我认为只使用阻塞读取来构建你想要的东西会很简单。试试吧。我认为这是一部分Sequelize 的 dataLoader 做了什么。)

无法对 Promises 进行乘法运算。没有办法等待一个本身不是异步的异步值。即使是严格意义上 async/await 不存在的事件,也需要一些异步外观 回调模式,两者都不是阻塞的,因此两者都不能使该语句起作用。

可以工作,但它强制每个调用者管理延迟加载:

order.shipmentCost = (await order.weight) * 4.5

这种方法会扭曲你的整个生态系统。调用者在需要时简单地调用 read & save 会好得多。

或者您可以创建一个在 getter 内工作的发电机,但您仍然需要为每个 属性 的第一次访问明确地“启动泵”,这将使“幻想”声明起作用,但会产生一个可怕的预声明 awaits。同样,最好只使用 readsave.


我认为您所希望的在 javascript 内是不可能的,因为阻塞和非阻塞行为不是透明的,也无法做到。任何异步机制最终都将表现为非标量。

您需要创建自己的预编译器,例如 JSX,它可以将幻想代码转换为 async/aware 垃圾。


严肃的建议:使用现成的持久性库而不是自己开发

  1. 数据持久化问题 space 充满了许多非常困难的问题和边缘情况。你必须解决比你想象的更多的问题。
  2. 除非你的整个项目是“构建更好的持久性技术”,否则你不会构建比现有的更好的东西,这意味着构建你自己的只是获得劣质解决方案的最慢方法。
  3. 您编写的代码越多,需要修复的错误就越多。 (您正在为这个神奇的持久性库编写测试,对吧?)

如果您正在尝试构建一个真正的应用程序并且您只需要与 Mongo 交互,请花 15 分钟在 npm 上购物然后继续。人生如此短暂。没有人会关心你的手写数据库层有多“酷”几乎 像 ActiveRecord(除了一些自以为是的定制 错误 缺失的功能——所有这些都会成为他人甚至你自己的障碍)。