0

这是我用来检查用户是否通过身份验证的访问功能的示例。

access = function(id, user_id, callback) {
  docs.findOne({
    _id: id
  }, function(err, doc) {
    if (doc.user.indexOf(user_id) != -1) {
      callback("authenticated")
    } else {
      callback();
    }
  });
}

我将它与这样的回调模式一起使用。

access(id, user, function (status) {
  if (status == 'authenticated') doSomething()
})

我发现写起来有点无聊,因为每次使用访问函数时确实需要检查回调状态。我想要一种更好的方法来使用访问函数,以便在回调中假设身份验证。像这样的东西?

access(id, user, function () {
  doSomething()
}).err(function () {
  doSomethingElse()
})
4

3 回答 3

3

如果你想要半小时视频形式的 Promise 介绍,我建议我在 JSConf.eu 发表演讲:http: //youtu.be/qbKWsbJ76-s

我从您的问题中得到的印象是您以前没有真正看过承诺(以及其他一些不是其他人都有的答案)。

JavaScript 承诺在Promises/A+规范中定义。它非常容易阅读,因此值得一看。并非所有承诺都遵循此规范(jQuery 是唯一真正值得注意的例外),但您可以在此处找到兼容实现的列表

作为新人:

如果你想看看 Promise 是如何实现的,Promise是最简单的一种(它也是最快的性能之一)。免责声明:我写了这个

不过,Promise 非常有限,因此如果没有大量扩展,它就没有多大用处。我建议您从Q开始,因为它是最受欢迎的之一,并且具有许多使其使用起来更加简单的功能。Q 也最适合未来规范中的大多数想法。

如果您使用 Mongoose 作为您的数据库驱动程序,它带有自己的 Promises/A+ 实现,因此您可以使用它:

access = function(id, user_id) {
  return docs.findOne({
    _id: id
  })
  .then(function(doc) {
    if (doc.user.indexOf(user_id) == -1) {
      throw new Error('User Not Found')
    }
  });
}

这里发生的docs.findOne是返回一个“承诺”,因为它是在没有回调的情况下调用的。附加的处理程序.then添加了一个回调。它还返回一个新的 Promise,第一个 Promise 中的任何错误都会自动传播到新的 Promise。如果在回调中抛出错误,则新的承诺被“拒绝”。如果回调返回一个值,那么新的 Promise 将用该值“实现”。

像这样定义了我们的函数后,我们可以调用它:

access(id, user_id)
  .then(function () {
    doSomething();
  });

如果在某个时候我们想要处理该错误,我们可以通过附加错误处理程序来实现:

access(id, user)
  .then(function () {
    doSomething()
  }, function (err) {
    doSomethingElse()
  })

唯一的问题是,如果doSomething抛出错误,它将被静音(这很糟糕)。如果您完成了将.then调用链接到一个承诺,您需要结束该链。

如果您使用的是 mongoose 内置的 Promise,那么您可以调用end

access(id, user)
  .then(function () {
    doSomething()
  }, function (err) {
    doSomethingElse()
  })
  .end();

如果您使用的是 Q 承诺,那么您将调用完成

access(id, user)
  .then(function () {
    doSomething()
  }, function (err) {
    doSomethingElse()
  })
  .done();

如果你有一个想要转换为 Q 承诺的猫鼬承诺,你可以简单地将它传递给Q

Q(access(id, user))
  .then(function () {
    doSomething()
  }, function (err) {
    doSomethingElse()
  })
  .done();

如果你不使用猫鼬

如果您不使用 Mongoose,并且需要从头开始创建 Q 承诺,请使用Q.promise

var promise = Q.promise(function (resolve, reject) {
  docs.findOne({
    _id: id
  }, function(err, doc) {
    if (doc.user.indexOf(user_id) != -1) {
      resolve("authenticated")
    } else {
      reject(new Error("User Not Found"));
    }
  });
})

还有一个处理节点样式 API 的快捷方式:

var findOne = Q.denodeify(docs.findOne);
var promise = findOne({_id: id});

设计推理

最后,如果你想知道为什么 Promise 会以它们的方式工作,或者你认为它们的设计在某些方面很愚蠢,那么https://github.com/kriskowal/q/blob/master/design/README.js是一个很好的指南. 它会带你从头开始开发一个 Promise 库,从你认为“回调还不够好”的地方开始,一直到一个完整的 Promise 库。

于 2013-05-29T22:21:14.463 回答
0

让我们分开:

access(id, user, function () {
  doSomething()
}).err(function () {
  doSomethingElse()
});

意思是一样的

var ret = access(id, user, function () {
  doSomething()
});

ret.err(function () {
  doSomethingElse()
})

所以,err(...)会一直被调用 - 不是你想要的。

关于什么

var Access = function ()
{
   this.errorHandler = null;

   this.registerErrorHandler = function (errh)
   {
      this.errorHandler = errh;

...
   this.authenticate = function (...)
   {



       // if not authenticated
       this.errorHandler(....)

只是一个想法?this.errorHandler 也可以是处理程序数组等。

为了打电话,你需要做:

myAccess = new Access();
myAccess.registerErrorHandler(xyz);
myAccess.authenticate(.....);
于 2013-05-29T20:29:28.777 回答
0

我相信 Mongoose 会为其所有查询函数返回 Promise,所以我认为类似下面的方法会起作用:

var access = function(id, user_id, callback) {
  return docs.findOne({_id: id}).then(function (doc) {
    if (doc.user.indexOf(user_id) != -1) throw(new Error("Wrong user_id."))
  }) // not handling any errors here
}

然后你可以像这样使用它:

access(id, user).then(function () {
  doSomething()
}, function (error) { // this "onRejected" handler is called when findOne fails, 
  console.log(error) // or if user_id doesn't match 
  doSomethingElse() // maybe decide what to do based on the type of error?
})

如果您使用的不是 Mongoose,而是“本机”MongoDB 客户端,那么您需要先自己创建一个 Promise。有很多图书馆可以这样做。我建议寻找一个符合 Promises/A+ 的库。大多数都很容易识别,因为他们的主页(或自述文件)突出显示了一个黄色方块,上面写着“then”。

于 2013-05-29T21:31:04.467 回答