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

Javascript 将父作用域中的变量传递给回调函数,javascript,ajax,closures,firebase,Javascript,Ajax,Closures,Firebase,这更像是一个JavaScript闭包问题,而不是Firebase问题。在下面的代码中,Firebase回调无法识别父作用域中的变量myArr function show_fb() { var myArr = []; var firebase = new Firebase('https://scorching-fire-6816.firebaseio.com/'); firebase.on('child_added', function(snapshot) {

这更像是一个JavaScript闭包问题,而不是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;
};

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

程序如下:

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

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

例如:

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

    • 回调识别/修改
      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
      }
      
      现在可能更容易看到发生了什么

    • 你为
      child\u added
      注册了一个监听器,该监听器将调用
      on\u post\u added
      为你的Firebase添加的每个帖子
    • 这将导致对服务器的调用,这可能需要很长时间才能返回
    • 同时,您的JavaScript代码将继续并
    • 记录阵列,该阵列在此阶段仍然为空
    • 然后返回一个空数组
    • 现在,在某个时刻,服务器返回新值并调用回调
    • 这意味着我们可以毫无问题地将其添加到阵列中
    • 并将其记录到控制台显示预期值
    • 像这样处理异步代码/回调需要一些时间来适应,但对于使用Firebase或任何其他类似AJAX或事件驱动技术来说至关重要。将回调代码放入一个单独的函数中有时会使查看发生了什么变得更容易

      在Firebase的情况下,它也可能有助于认识到事件之所以被称为
      child\u 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
      }
      

      谢谢你的明确回答!我最喜欢你的答案,但由于缺少徽章点数(提示),我无法对其进行投票。鉴于你问了这个问题,你应该可以通过单击其左侧的复选标记来接受我的答案。谢谢你的回答,弗兰克,这对我正在打造的比赛很有帮助。