在 ORM 中实现(继承)Promise 接口

Implementing (Inheriting) Promise interface in an ORM

我想承诺 ODM/ORM。您将如何在具有其他方法(例如 find()insert()update() 等的同时实现 promise 接口。所以您可以

var Users = Collection('users')
Users.find({name: 'joe'})
  .then(users => users.update({name: 'jim'))
  .then(console.log)

我正在考虑从 Promise 继承,但是您如何将 then() 自定义为 return 您的 ORM 实例,以确保我们正在使用该实例进行所有查询顺序。 现在我正在使用组合,但是我必须代理每一个越来越丑陋的方法调用。

例如:

var Promise = require('bluebird')

var Collection = function(Storage, name) {
    this.promise = new Promise(function(resolve, reject) {
            self.resolve = resolve
            self.reject = reject
        })
}

Collection.prototype.find = function(query) {
    // async query stuff here
    Storage.doAsyncQueryStuff(function (err, results) {
        err && this.reject(err)
        this.resolve(results)
    })
}

Collection.prototype.then = function(callback) {
    var self = this
    this.promise.then(function() {
        callback && callback.apply(self, arguments)
    })
    return this
}

我想做的是:

var inherits = require('util').inherits
var Promise = require('bluebird')

var Collection = function(Storage, name) {
    var self = this
    // error here
    Promise.call(
        this,
        function(resolve, reject) {
            self.resolve = resolve
            self.reject = reject
        })
}
inherits(Collection, Promise)

我似乎无法初始化 Promise。或者我应该以不同的方式这样做吗?

经过一番研究后,我发现在 ORM 实例中继承承诺并不是一个好主意,原因如下:

Promise 递归解析,每个 returning 一个 new promise 从最后一个解析。

例如:

var debug = console.log

var promise1 = new Promise((r, e) => {
    r(1)
})
var promise2 = new Promise((r, e) => {
    r(2)
})

var promise3 = promise1.then(data => promise2)

debug('promise1 === promise1', promise1 === promise1) // true
debug('promise3 === promise1', promise3 === promise1) // false
debug('promise3 === promise2', promise3 === promise2) // false

promise1会先解析promise2,将解析后的值作为promise1的解析值。然后 promise1 将 return 一个新的 promise (promise3) 解析为 promise1 的值。

这很重要,因为承诺解析状态是不可变的,但承诺是可链接的。

为了高效 return ODM 中每个 then() 调用的新承诺同时保持其当前状态将需要优化,例如使 ORM 状态数据不可变或从全局存储(注册表)引用,同时保持当前 query 唯一(过滤器、排序、加载关系)等。将像 then()、catch() 这样的承诺接口组合到 ORM 上更简单,因为 Promise 规范非常宽容。

阻止通过继承扩展 bluebird,因为存在检查以仅允许由 Promise 类型的对象创建实例。 https://github.com/petkaantonov/bluebird/issues/325

Bluebird 以及 FF 中内置的 Promise,Chrome 和 Node.js 无法通过 ES5 继承进行扩展。它们都需要 Promise 的实例来实例化。

ECMA262定义了可继承的Promise对象。 http://www.ecma-international.org/ecma-262/6.0/#sec-promise-constructor

使用 ES6 class 语法,您可以扩展内置的浏览器承诺。

class MyPromise extends Promise {} 

这可能适用于 Node.js 使用 Babel。

您可以通过直接在 ES5 中设置 __proto__ 属性 来扩展 bluebird 和 built-in promise。

/**
 * @class   MyPromise
 * @extends Promise
 */
var MyPromise = function () {
  var resolve, reject
  var promise = new Promise(function(_resolve, _reject) {
      resolve = _resolve
      reject = _reject
    })
  promise.__proto__ = this.__proto__
  promise.resolve = resolve
  promise.reject = reject
  return promise
}

MyPromise.prototype = Object.create(Promise.prototype, { constructor: { value: MyPromise } })

MyPromise.prototype.call = function() {
    this.resolve(new Date)
}

MyPromise.all = Promise.all
MyPromise.cast = Promise.cast
MyPromise.reject = Promise.reject
MyPromise.resolve = Promise.resolve

module.exports = MyPromise

虽然我不推荐它,因为 __proto__ 不是标准的,但得到广泛支持。