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

IT技术 javascript ajax closures firebase
2021-03-16 15:05:21

这更像是一个 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个回答

回调可以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,它将调用on_post_added添加到您的 Firebase 的每个帖子
  2. 这将导致对服务器的调用,这可能需要很长时间才能返回
  3. 同时,您的 JavaScript 代码会继续并...
  4. 记录数组,在这个阶段它仍然是空的
  5. 然后因此返回一个空数组
  6. 现在在某个时候服务器返回新值并调用您的回调
  7. 这意味着我们可以毫无问题地将它添加到数组中
  8. 并将其记录到控制台显示预期值

处理这样的异步代码/回调需要一些时间来适应,但对于使用 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
}
鉴于您提出了这个问题,您应该能够通过单击它左侧的复选标记来接受我的回答。参见meta.stackexchange.com/questions/5234/...
2021-05-05 15:05:21
感谢弗兰克的回答 - 它对我正在构建的游戏有所帮助。
2021-05-07 15:05:21
感谢您的明确答复!最喜欢您的答案,但由于缺少徽章点数(提示)而无法投票。
2021-05-08 15:05:21

child_ added 事件不会立即执行,因此不是同步的,您不能依赖它在函数末尾的日志调用之前执行。

程序是:

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

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

例如:

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