在ES6 + babel中使用蓝鸟宣传导入的类(构造函数)

时间:2015-07-13 19:47:11

标签: javascript node.js constructor promise bluebird

假设我创建或拥有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 = ???

我怎么做到最好?更改库签名并不是一个好的选择,创建工厂方法似乎也很难看。

2 个答案:

答案 0 :(得分:6)

我对此非常感兴趣所以我将从它开始:不要在构造函数中执行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
};

哪个允许你使用返回值和promise,promise只会有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;
   }
 }

答案 1 :(得分:0)

你不能直接宣传构造函数(我知道),但你可以通过工厂方法解决这个问题:

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库。