在ES6 + babel中使用bluebird承诺导入类(构造函数)
Promisify imported class (constructor) with bluebird in ES6 + babel
假设我创建或拥有一个node.js库lib.js
export class C {
constructor(value, callback) {
callback(false, `Hello ${value}`);
}
task(value, callback) {
callback(false, "returned " + value);
}
}
重要的部分是类的构造函数需要接受回调,因为它进行数据库连接和文件I/O。如果我现在导入并使用库回调样式,一切都很好(参见下面的c1
)。
我真的很想承诺我使用的库使对象构造更方便(实际上它是一大堆类和方法)。
然而,我找不到一种方法来new
类正确地承诺安全很好。
import Promise from 'bluebird';
import * as lib from './lib';
Promise.promisifyAll(lib);
// old style -- works as expected
const c1 = new lib.C("c1", (e, v) => {
console.log(c1, e, v);
});
// assuming c1 got initialized, .task() also works
c1.task("t1", console.log);
c1.taskAsync("t2").then(() => console.log("also works"));
// But how to do this properly with promises?
const c2 = new lib.C("c2"); c2.then(console.log); // clearly doesn't work, lack of callback
const c3 = new lib.CAsync("c3"); c3.then(console.log); // "cannot read property apply of undefined"
const c4 = ???
我该如何做得最好?更改库签名不是一个好选择,创建工厂方法似乎也很难看。
我对此有强烈的感觉,所以我将从它开始:不要在构造函数中做IO,将IO和构造函数绑定在一起是一个坏主意。
也就是说,如果您必须这样做,因为库超出了您的控制范围,并且可以接受失去以同步方式构建对象的能力,则可以:export class C {
constructor(value, callback) {
callback(false, `Hello ${value}`);
}
task(value, callback) {
callback(false, "returned " + value);
}
}
承诺时:
import Promise from 'bluebird';
import * as lib from './lib';
Promise.promisifyAll(lib);
var old = lib.C; // reference the constructor
lib.C = function(value){ // override it
o; // object we'll later return, populate in promise constructor
var p = new Promise(function(resolve, reject){
// the promise constructor is always sync, so the following works
o = new old(value, function(err, data) {
if(err) return reject(err);
resolve(data);
});
});
// THIS IS THE IMPORTANT PART
o.then = p.then.bind(p); // make the object a thenable,
return o
};
这将让你同时使用返回值和承诺,承诺将只有一个then
,所以你可能想要Promise.resolve
它得到一个"真正的"承诺,而不是一个对象的属性和一个承诺。
var o = new lib.C(); // get object
o.then(function(data){
// access data
});
这可以被提取成一个模式:
function promisifyConstructor(cons){
return function(...args) => { // new constructor function
let o;
let p = new Promise((resolve, reject) => {
// delegate arguments
o = new cons(...args, (err, data) => err ? reject(err) : resolve(data));
});
o.then = p.then.bind(p);
return o;
}
}
您不能直接承诺构造函数(我知道),但您可以通过工厂方法轻松解决这个问题:
function createC(value) {
return new Promise(function (res, rej) {
var c = new C(value, function (err, val) {
if (err) {
rej(err);
} else {
res(val); // or res(c) if you prefer
}
});
});
}
我认为没有比这更漂亮的方法了,一个构造良好的工厂不应该太丑。您可以将工厂泛化为采用该形式的任何构造函数,但这样您就接近了完全的DI,并且可能值得寻找一个承诺友好的DI库。
相关文章:
- 如何使用url加载程序在webpack中导入多个图像
- 我的职位回报太快了,如何做出承诺
- 打破承诺链的好方法是什么
- 如何将JSON数据导入我的ejs模板
- 从函数返回角度承诺
- 如何将不可变的js导入angular 2(alpha)
- 将数据从javascript文件导入VB.Net页面
- 我怎样才能获得承诺的价值
- 延期承诺值未更新/解析/延期
- 导入jQuery脚本获胜'我不处理html文件
- 在承诺链中处理早期回报的最佳方式
- javascript导入的最佳实践是什么
- 承诺在非节点式回调上使用Bluebird
- 将CSV文件从URL导入Node.js
- 简单的ES6承诺问题-交换解决和拒绝参数
- 组合承诺和非承诺值
- 带有对象/原型的链式承诺(Q延期)
- 空承诺在 ES6 中使用导入的类返回
- 系统.导入承诺链接
- 在ES6 + babel中使用bluebird承诺导入类(构造函数)