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

时间:2014-10-10 10:47:03

标签: javascript ajax closures firebase

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

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;
};

3 个答案:

答案 0 :(得分:9)

回调是完全正确地识别/修改myArr。问题是当你的"没有工作"标记的console.log(myArr)执行时,回调还没有被解雇。

让我们改变你的代码:

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
}

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

  1. 您为child_added注册了一个监听器,该监听器将为添加到您的Firebase的每个帖子调用on_post_added
  2. 这将导致对服务器的调用,这可能需要很长时间才能返回
  3. 同时您的JavaScript代码会继续......
  4. 记录此阶段仍为空的数组
  5. 然后返回一个空数组
  6. 现在在某个时刻,服务器返回新值并调用您的回调
  7. 这意味着我们可以毫无问题地将其添加到阵列
  8. 将其记录到控制台会显示预期值
  9. 处理这样的异步代码/回调需要一些人习惯,但对于使用Firebase或任何其他类似AJAX或事件驱动的技术至关重要。将回调代码放入单独的函数有时可以更容易地看到正在进行的操作。

    对于Firebase,它也可能有助于意识到事件被调用child_added是有原因的。只要孩子被添加到Firebase,就会调用它,而不仅仅是在您第一次注册回调时。所以几分钟后,当其他一些客户添加一个孩子时,你的回调仍然会触发,向myArr添加一个新的孩子。在那个阶段,上面步骤4和5中的代码将长期执行,不会再执行。

    解决方案很简单:在将一个孩子添加到回调中之后放置您想要做的任何事情:

    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
    }
    

答案 1 :(得分:1)

child_added事件不是立即执行的,因此不是同步的,并且在函数结束时的日志调用之前,你不能依赖它来执行。

程序是:

  • 定义myArr
  • 实例化Firebase
  • 为child_added
  • 分配事件处理程序
  • 记录myArr的值
  • 返回myArr - 功能结束
  • 现在在此之后的某个时刻,会触发child_added事件,该事件将推送到您的数组,但正如您所看到的,此时show_fb()函数已经完成执行。

答案 2 :(得分:0)

如果Firebase进行ajax调用(可能确实如此),则在return语句之后调用回调函数(快照){..}。所以函数show_fb总是返回[]。

例如:

  • 执行此语句:var x = show_fb();
    • show_fb创建空数组
    • function创建ajax调用
    • 函数返回myArr(此时为空)
    • 变量x引用myArr(数组仍为空)
    • 调用callback并将新值插入x(x和myArr具有相同的实例)