【问题标题】:Implementing (Inheriting) Promise interface in an ORM在 ORM 中实现(继承)Promise 接口
【发布时间】:2017-06-01 11:00:09
【问题描述】:

我想承诺一个 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() 以返回您的 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。还是我应该以不同的方式做这件事?

【问题讨论】:

  • I want to promisify - 我认为蓝鸟promisify 方法不合适? bluebirdjs.com/docs/api/promise.promisify.htmlbluebirdjs.com/docs/api/promise.promisifyall.html
  • promisify 和 promisifyAll 将使函数返回一个 Promise 实例。我需要一个继承返回的 promise 方法的 ODM 实例,这样我就可以将更多的 ODM 方法链接到 Promise。例如:Users.insert(...).catch(...).delete(...).then()。使用 Promisify,一旦执行 then() 或 catch() 就不能调用另一个 ODM 方法。
  • 我不明白您为什么希望 Collection 继承自 Promise。你什么时候/为了什么使用Users.then(??? => { … })Collection 应该是一个普通的类,每个 find/insert/update 方法应该为其各自的结果返回一个承诺。不是新系列。
  • 使集合正常工作并保持状态 - 不可变或其他。然后你可以让它更像 FP 并控制数据流。例如。 Users.create().then(log).catch(retryAfterAWhile).insert() 而不是 Users.create().then(state => Users.insert())。但你是对的,我可能想多了。我基本上在寻找类似 highland.js 的东西,但寻找的是 ODM 和像 Promise 这样的规范接口。我是不是误解了 Promise?

标签: javascript promise bluebird odm


【解决方案1】:

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

Promise 递归解析,每个返回一个 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 然后将返回一个新的 Promise (promise3) 解析为 Promise1 的值。

这很重要,因为 Promise 解析状态是不可变的,而 Promise 是可链接的。

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

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

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

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

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

class MyPromise extends Promise {} 

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

您可以通过直接在 ES5 中设置 __proto__ 属性来扩展 bluebird 和内置 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__ 虽然受到广泛支持,但不是标准的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-17
    • 2021-01-29
    • 1970-01-01
    • 1970-01-01
    • 2016-09-12
    相关资源
    最近更新 更多