我有一个按钮,它执行一个带有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.
})
}
任何解决方案?我对承诺没有多少经验,但我找不到任何相关的东西。欢呼声。
答案 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();
});
};