在 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__
不是标准的,但得到广泛支持。
我想承诺 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__
不是标准的,但得到广泛支持。