承诺只适用于当时的功能

时间:2017-01-27 13:07:16

标签: javascript angularjs firebase ionic-framework firebase-realtime-database

我有一个按钮,它执行一个带有promise的函数,该函数在html中获取并显示来自firebase的数据(我正在使用angularJS,ionic和firebase)。

问题是:如果我之后没有包含.then(function(){}),则会以非同步方式执行promise,这意味着我必须再次单击该按钮,以便数据显示在html中

我希望将数据放在promise之后的范围内(从firebase获取数据),但出于某种原因,只有在我之后添加.then函数时才会有效。

但是,数据在控制台中正常显示,但不在html中显示(意味着我认为该功能未附加到范围内)。

这是一段代码:

$scope.displayChat = function () {
    var userId = firebase.auth().currentUser.uid; // Get ID
    var deferred = $q.defer()

    var db = firebase.database();
    var ref = db.ref("12346787");

  ref.on("value", function(snapshot) {
           console.log(snapshot.val());
           $scope.chatArray = snapshot.val();
           deferred.resolve()

       }, function (errorObject) {
           console.log("The read failed: " + errorObject.code);
       })

   return deferred.promise.then(function(){
        // Removing this empty .then(function(){}) function
        // will result in asynchronousity.
        // just "return deferred.promise;" doesn't work.
    })
}

任何解决方案?我对承诺没有多少经验,但我找不到任何相关的东西。欢呼声。

3 个答案:

答案 0 :(得分:1)

承诺的目的是管理异步方法,所以我真的不明白这个问题......

此外,通常必须执行displayChat中的代码,之后只能执行回调。您应该返回promise,这使您能够在确定所需的异步方法完成后执行回调。

答案 1 :(得分:1)

当范围的更改由AngularJS框架外部的事件完成时,框架需要执行$ apply以启动摘要周期来更新DOM。

.then服务承诺的$q方法会自动启动必要的摘要周期。在这种情况下,displayChat函数返回的promise将被丢弃,并且不会启动摘要周期。随后单击该按钮将启动摘要循环。

将来,有人可能希望链接displayChat函数返回的承诺。我建议通过返回正确的承诺并将范围的任何更改移动到.then方法,使函数更具通用性。

$scope.displayChat = function () {
    var userId = firebase.auth().currentUser.uid; // Get ID
    var deferred = $q.defer()

    var db = firebase.database();
    var ref = db.ref("12346787");

    //ref.on("value", function(snapshot) {
    //USE once
    ref.once("value", function(snapshot) {
           console.log(snapshot.val());
           //$scope.chatArray = snapshot.val();
           deferred.resolve(snapshot.val());

       }, function (errorObject) {
           console.log("The read failed: " + errorObject.code);
           //ADD rejection case
           deferred.reject(errorObject);
       })

   return deferred.promise.then(function(chatArray){
       //Move scope changes here
       $scope.chatArray = chatArray;
       //RETURN to chain data
       return chatArray;

       // Removing this empty .then(function(){}) function
       // will result in asynchronousity.
       // just "return deferred.promise;" doesn't work.
   })
}

另外,为避免内存泄漏,请使用ref.once代替ref.on,并确保在错误情况下拒绝承诺。

答案 2 :(得分:0)

Promise用于推迟执行某些逻辑,直到承诺得到满足为止 - 即:您已从数据库收到结果。在您的情况下,您已经推迟了控制台显示并在ref.on中设置了$ scope变量。承诺代码是多余的。

您的结果显示在控制台中的事实证明您已收到结果。更新范围中的数据时,在发生摘要周期之前不会显示。大多数情况下,Angular可以自动确定何时需要运行摘要周期。在那些没有的情况下,您可以通过将范围相关逻辑包装在超时中来强制它,在这种情况下,您的代码将如下所示:

$scope.displayChat = function () {
var userId = firebase.auth().currentUser.uid; // Get ID

var db = firebase.database();
var ref = db.ref("12346787");

ref.on("value", function(snapshot) {
       console.log(snapshot.val());
       $timeout(function () {
            $scope.chatArray = snapshot.val();
       });

   }, function (errorObject) {
       console.log("The read failed: " + errorObject.code);
   })

}

您使用promise .then方法恰好触发了摘要周期。承诺本身并没有做任何事情。

如果您的目的是在快照可用时将快照传递给调用者,那么当承诺发挥作用时,将按以下步骤完成:

    $scope.displayChat = function () {
    var userId = firebase.auth().currentUser.uid; // Get ID
    var deferred = $q.defer()

    var db = firebase.database();
    var ref = db.ref("12346787");

    ref.on("value", function(snapshot) {
            deferred.resolve(snapshot)

       }, function (errorObject) {
           console.log("The read failed: " + errorObject.code);
       })

   return deferred.promise;
};

$scope.callDisplayChat = function () {
    $scope.displayChat().then(function (result) {
        $scope.chatArray = result.val();
    });
};