【问题标题】:Mongoose promise in user provider object with prototype functions具有原型功能的用户提供者对象中的猫鼬承诺
【发布时间】:2014-11-27 22:44:16
【问题描述】:

抱歉,我无法提出一个直截了当的问题/标题,但这就是问题所在。我有以下构造:

var userProvider=function(login){
   this.getUser=mongoose.find(login).exec();
}
userProvider.prototype.doStuffWithUserData=function(){
   this.getUser.then(function(user){
       ...
   });
} 
userProvider.prototype.doOtherStuffWithUserData=function(){
   this.getUser.then(function(user){
       ...
   });
} 

有没有更好的方法,这样我就不需要在每个原型函数中调用承诺,尽管原型函数只在数据存在之前被评估?

【问题讨论】:

  • 如果你重复它,你可以将它提取到一个装饰器中。
  • Is it bad practice to have a constructor function return a Promise? 的可能重复项 - 如果这有助于解决您的问题,我很乐意作为一个骗子关闭,否则我可以使用 Benjamin 提到的装饰器技术发布答案。
  • 我会选择不好的做法,谢谢:)
  • @Bergi 他的构造函数没有返回一个承诺。
  • @BenjaminGruenbaum:你是对的,但它似乎是相同的设置 - 方法依赖于在构造函数中完成的异步副作用。当然,我们不知道doStuffdoOtherStuff 到底是什么,但它们最好不要尝试操作实例或调用其他方法;否则这个类会变得一团糟。

标签: javascript node.js mongoose promise


【解决方案1】:

有没有更好的方法,只有在数据存在时才评估原型函数?

我建议不要在构造函数中执行 find 副作用并在此处创建 promise,而是将 mongoose.find(login).exec() 传递给构造函数的结果,如 @ 中所述987654321@

我会选择不良实践案例

为避免重复,您可以像这样创建原型方法:

function userProviderMethod(n, m) {
    UserProvider.prototype[n] = function() {
        var args = Array.prototype.slice.call(arguments),
            that = this;
        return this.getUser.then(function(user) {
            args.unshift(user);
            return m.apply(that, args);
        });
    };
}

function UserProvider(login){
    this.getUser = mongoose.find(login).exec();
}
userProviderMethod("doStuffWithUserData", function(user /*, … */) {
    // …
});
userProviderMethod("doOtherStuffWithUserData", function(user) {
    // …
});

请注意,当.getUser 确实被拒绝时,这些“方法”实际上都不会被执行。

【讨论】:

  • 嘿,我们相隔 20 秒得出了几乎相同的解决方案。干杯:)
【解决方案2】:

以下是装饰的方法。这很棘手,因为当您创建函数时,promise 不可用:

function whenReady(fnToRun){
    return function runsWhenReady(){ // the decorated function
        // keep track of arguments
        var args = Array(arguments.length + 1); // inline slice is much faster
        for(var i = 0; i < arguments[i]; i++) args[i+1] = arguments[i];
        return this.getUser.then(function(user){
            args[0] = user;
            return fnToRun.call(this, args); // append user and call with args
        }.bind(this)); // maintain context)
    };
}

这会让你这样做:

userProvider.prototype.doStuffWithUserData = whenReady(function(user){
    // user is available here 
});

myUserProviderInstance.doStuffWithData(); // inside the call user is available

userProvider.prototype.otherStuff = whenReady(function(user, x){
    // user is available here 
});

myUserProvider.otherStuff(15); // x will be 15 and user will be available, promise returned

这种方法可以推广到更通用的whenReady,它采用“waitFor”参数。还值得一提的是,如果您使用像 Bluebird 这样的库,它已经附带了 bindmethod,这让您可以更轻松地做到这一点。

【讨论】:

  • 如果你真的想追求速度,你可以使用var args = new Array(1),这样你就可以避免concat 调用,而是做一个任务:-)
猜你喜欢
  • 2013-09-15
  • 1970-01-01
  • 2018-05-09
  • 2015-05-12
  • 1970-01-01
  • 2015-06-27
  • 1970-01-01
  • 2014-03-27
  • 2012-12-14
相关资源
最近更新 更多