2016-11-19 58 views
2

我正在使用Firebase以及angularJS來獲取用戶列表。我可以從我與once()函數讀取數據庫的所有用戶,但我想不出爲什麼userList返回undefined下面爲什麼Firebase在once()函數之外失去引用?

.service('userService', [function() { 
    this.getUsers = function() { 
     var users; 
     var userList; 
     var ref = firebase.database().ref('/users/'); 
     ref.once('value').then(function(snapshot) { 
      users = snapshot.val(); 
      for(var key in users) { 
       users[key].id = key; 
       // do some other stuff 
      } 
      console.log(users); // outputs all users 
     }).then(function(){ 
      userList = users; 
      console.log(userList); // outputs all users 
     },(function(error){ 
      alert('error: ' + error); 
     }); 
     console.log(userList); // outputs 'undefined' 
    } 
}]); 

我迫不及待地分配我userList變量,直到我做處理users,但沒有運氣。

這裏有一些重要的信息,我錯過了承諾/回調的位置,我在文檔中找不到它;有人能幫我理解我的問題嗎?

回答

1

你需要考慮異步:

.service('userService', [function() { 
    this.getUsers = function() { 
     var users; 
     var ref = firebase.database().ref('/users/'); 

     <!-- this happens ASYNC --> 
     ref.once('value', function(snapshot) { 
      users = snapshot.val(); 
      for(var key in users) { 
       users[key].id = key; 
       // do some other stuff 
      } 
      console.log(users); // outputs all users 
     },function(error){ 
      alert('error: ' + error); 
     }); 
     <!-- end async action --> 

     console.log(users); // outputs 'undefined' 
    } 
}]); 

我敢打賭,如果你這樣做,你會被罰款:

.service('userService', [function() { 
    this.getUsers = function() { 
     var users; 
     var ref = firebase.database().ref('/users/'); 

     <!-- this happens ASYNC --> 
     ref.once('value', function(snapshot) { 
      users = snapshot.val(); 
      for(var key in users) { 
       users[key].id = key; 
       // do some other stuff 
      } 
      console.log(users); // outputs all users 
     },function(error){ 
      alert('error: ' + error); 
     }); 
     <!-- end async action --> 

     window.setTimeout(function() { 
      console.log(users); // outputs 'undefined' 
     }, 1500); 
    } 
}]); 

每直率的評論澄清:

我應進一步明確那setTimeout只會證明這是一個時間問題。如果你在你的應用中使用setTimeout,你可能會有一段糟糕的時間,因爲你無法可靠地等待n毫秒的結果,你需要得到它們,然後發出回調或解決承諾後,獲得快照數據。

+0

謝謝@imjared,我包含一些額外的邏輯,以確保我的異步函數在我的代碼中成功完成後填充'userList' –

+2

'setTimeout()'可能會或可能不會工作(主要取決於您的網絡延遲) ,但它從來沒有**這個問題的正確解決方案。正確的解決方案是將需要「用戶」列表的代碼移動到回調/然後塊中。 –

4

問題是(如上所述),數據是從Firebase異步讀取的。所以代碼不會按照您的想法執行。這是最容易看到,只有幾個日誌語句簡化IT:

.service('userService', [function() { 
    this.getUsers = function() { 
     var ref = firebase.database().ref('/users/'); 
     console.log("before attaching listener"); 
     ref.once('value').then(function(snapshot) { 
      console.log("got value"); 
     }); 
     console.log("after attaching listener"); 
    } 
}]); 

這樣做的結果應該是:

連接監聽器

了後附聽衆

前值

瞭解訂單在這裏執行應該完全解釋爲什麼你不能打印用戶列表後,你剛剛連接了監聽器。如果沒有,我建議也閱讀這個偉大的答案:How do I return the response from an asynchronous call?

現在的解決方案:你會要麼需要用到的用戶列表回調返回一個承諾。

使用用戶列表回調

這是爲了處理異步代碼的最古老的方式:移動需要用戶列表步入回調的所有代碼。

ref.once('value', function(snapshot) { 
     users = snapshot.val(); 
     for(var key in users) { 
      users[key].id = key; 
     } 
     console.log(users); // outputs all users 
    }) 

你從「第一次加載用戶列表,然後打印其內容」,以「每當加載的用戶列表,打印其內容」重新定義你的代碼。定義上的差異很小,但突然間你完全有能力處理異步加載。

你也可以做同樣的承諾,就像你在你的代碼做:

ref.once('value').then(function(snapshot) { 
     users = snapshot.val(); 
     for(var key in users) { 
      users[key].id = key; 
      // do some other stuff 
     } 
     console.log(users); // outputs all users 
    }); 

但是使用諾擁有直接使用回調一個巨大的優勢:可以回報承諾

返回一個承諾

通常你不會希望把所有需要用戶到getUsers()函數的代碼。在這種情況下,你可以要麼傳遞迴調到getUsers()(我不會在這裏顯示,但它是非常相似的回調可以傳遞到once()可以返回從getUsers()一個承諾:

this.getUsers = function() { 
    var ref = firebase.database().ref('/users/'); 
    return ref.once('value').then(function(snapshot) { 
     users = snapshot.val(); 
     for(var key in users) { 
      users[key].id = key; 
      // do some other stuff 
     } 
     return(users); 
    }).catch(function(error){ 
     alert('error: ' + error); 
    }); 
} 

有了這項服務,我們就可以調用getUsers(),然後用這個承諾在用戶一旦他們加載獲得:

userService.getUsers().then(function(userList) { 
    console.log(userList); 
}) 

而且與你馴服的野獸異步。那麼......至少現在。即使經驗豐富的JavaScript開發人員偶爾會遇到困惑,所以如果需要一些時間來適應,也不用擔心。

相關問題