将父作用域中的变量传递给回调函数

问题描述:

这更像是一个 JavaScript Closure 问题而不是 Firebase 问题.在以下代码中,Firebase 回调无法识别父作用域中的变量 myArr.

This is more of a JavaScript Closure question than a Firebase question. In the following code, the Firebase callback isn't recognizing the variable myArr in the parent scope.

function show_fb() {
    var myArr = [];
    var firebase = new Firebase('https://scorching-fire-6816.firebaseio.com/');
    firebase.on('child_added', function(snapshot) {
        var newPost = snapshot.val();
        myArr.push(newPost.user);
        console.log(myArr); // works
    });
    console.log(myArr); // doesn't work. myArr in the firebase.on callback is
                        // not altering myArr
    return myArr;
};

回调可以很好地识别/修改 myArr.问题是,当你的不工作"标签 console.log(myArr) 执行时,回调还没有触发.

The callback is recognizing/modifying myArr perfectly fine. The problem is that when your "doesn't work"-labeled console.log(myArr) executes, the callback hasn't fired yet.

让我们稍微更改一下代码:

Let's change your code a bit:

var myArr = [];
function show_fb() {
    var firebase = new Firebase('https://scorching-fire-6816.firebaseio.com/');
    firebase.on('child_added', on_post_added); // steps 1-3
    console.log(myArr);                        // step 4
    return myArr;                              // step 5
};
function on_post_added(snapshot) {             // step 6
    var newPost = snapshot.val();
    myArr.push(newPost.user);                  // step 7
    console.log(myArr);                        // step 8
}

现在可能更容易看到发生了什么.

Now it might be a bit easier to see what's going on.

  1. 您为 child_ added 注册一个侦听器,该侦听器将为添加到 Firebase 的每个帖子调用 on_post_ added
  2. 这将导致调用服务器,这可能需要很长时间才能返回
  3. 与此同时,您的 JavaScript 代码会继续……
  4. 记录在此阶段仍为空的数组
  5. 然后返回一个空数组
  6. 现在在某个时候服务器返回新值并调用您的回调
  7. 这意味着我们可以毫无问题地将它添加到数组中
  8. 并将其记录到控制台显示预期值
  1. You register a listener for child_added that will call on_post_added for every post that is added to your Firebase
  2. This will result in a call to the server, which may take a significant amount of time to return
  3. Meanwhile your JavaScript code continues and...
  4. Logs the array, which at this stage is still empty
  5. And then thus returns an empty array
  6. Now at some point the server returns the new value(s) and your callback is invoked
  7. Which means we can add it to the array without problems
  8. And logging it to the console shows the expected values

处理像这样的异步代码/回调需要一些时间来适应,但对于使用 Firebase 或任何其他类似 AJAX 或事件驱动的技术至关重要.有时将回调的代码放入一个单独的函数中,可以更容易地了解发生了什么.

Handling asynchronous code/callbacks like this takes some getting used to, but is crucial to working with Firebase or any other AJAX-like or event driven technology. Putting the callback's code into a separate function sometimes makes it a bit easier to see what's going on.

在 Firebase 的情况下,意识到事件被称为 child_ added 是有原因的.每当将孩子添加到 Firebase 时都会调用它,而不仅仅是在您第一次注册回调时调用.所以几分钟后,当其他一些客户端添加一个孩子时,你的回调仍然会触发,向 myArr 添加一个新孩子.在那个阶段,上面第 4 步和第 5 步中的代码将长期执行并且不会再次执行.

In the case of Firebase it may also help to realize that the event is called child_added for a reason. It is called whenever a child is added to the Firebase, not just when you first register your callback. So minutes later when some other client adds a child, your callback will still fire, adding a new child to myArr. At that stage the code in steps 4 and 5 above will long have executed and will not execute again.

解决方案很简单:在你的回调函数中加入你想要做的任何事情:

The solution is simple: put anything that you want to do after a child is added into your callback:

var myArr = [];
function show_fb() {
    var firebase = new Firebase('https://scorching-fire-6816.firebaseio.com/');
    firebase.on('child_added', on_post_added);
};
function on_post_added(snapshot) {
    var newPost = snapshot.val();
    myArr.push(newPost.user);
    console.log(myArr);
    // do whatever else you need to do for a new post
}