在javascript中从嵌套函数访问变量

时间:2014-02-27 16:48:06

标签: javascript nested-function

我想从函数

之外的回调中访问变量值
function test()
{
    var videoData=[];
    searchYTVideos("test1",0,function(vidYT){
       //concat to videoData
       videoData = videoData.concat(vidYT);

    });

    searchVideo("test2",0,function(vidDM){
        //concat to videoData
        videoData = videoData.concat(vidDM);
    });
    console.log(videoData);
}

但是,我得到一个空白值。如何将vidYT和vidDM的值连接到videoData

4 个答案:

答案 0 :(得分:0)

当浏览器点击console.log时,假设两个搜索功能都是异步的,那么videoData可能仍然为空,因为回调尚未执行。

  

欢迎来到JS的异步奇迹!

通过异步,你不能只做return数据,因此回调。

你可以做的是为你的搜索功能调用第三个函数,它检查两个回调是否都被执行。或者在另一个中嵌入一个电话。然后,您可以安全地console.log videoData {{1}}。这意味着将代码从通常的同步模式中分离出来。

答案 1 :(得分:0)

代码是异步的,因此console.log在调用回调之前正在执行。

您可以尝试嵌套回调:

var videoData=[];
searchYTVideos("test1", 0, function(vidYT) {
    //concat to videoData
    videoData = videoData.concat(vidYT);

    searchVideo("test2", 0, function(vidDM){
        //concat to videoData
        videoData = videoData.concat(vidDM);

        console.log(videoData);
    });
});

或者如果您不想嵌套它们,可以使用flags / counter和第三个函数来检查是否已调用回调:

var videoData=[];
var numCalled = 0;

searchYTVideos("test1",0,function(vidYT){
   //concat to videoData
   videoData = videoData.concat(vidYT);

   numCalled++;
   logData();

});

searchVideo("test2",0,function(vidDM){
    //concat to videoData
    videoData = videoData.concat(vidDM);
    numCalled++;
    logData();
});

function logData() {
    if(numCalled === 2) {
        console.log(videoData);
    }
}

就个人而言,我认为嵌套版本更容易理解。

答案 2 :(得分:0)

我怀疑问题不是范围(你的范围没有问题),而是同步。 searchYTVideossearchVideo都进行回调这一事实向我表明他们是asynchronous;也就是说,当JavaScript引擎有时间时,它们会工作,然后然后调用回调。如果您可以指定虚构的“步骤编号”,它可能看起来像这样:

1   var videoData=[];
2   searchYTVideos("test1",0,function(vidYT){
        //concat to videoData
15      videoData = videoData.concat(vidYT);

    });

3   searchVideo("test2",0,function(vidDM){
        //concat to videoData
23      videoData = videoData.concat(vidDM);
    });
4   console.log(videoData);
    // other stuff happens for a while...

请注意,在这个虚构的示例中,我先searchYTVideos完成,但没有任何内容表明它不是另一种方式:searchVideo首先完成,然后searchYTVideos完成了。

要解决此问题,您可以像其他人建议的那样链接这些功能,或者您可以使用承诺:

<!-- "Q" promises library -->
<script src="http://cdnjs.cloudflare.com/ajax/libs/q.js/1.0.0/q.js"></script>
<script>
    var videoData=[];
    var deferred1 = Q.defer();
    searchYTVideos("test1",0,function(vidYT){
       //concat to videoData
       videoData = videoData.concat(vidYT);
       deferred1.resolve();
    });

    var deferred2 = Q.defer();
    searchVideo("test2",0,function(vidDM){
        //concat to videoData
        videoData = videoData.concat(vidDM);
        deferred2.resolve();
    });

    Q.all([deferred1.promise, deferred2.promise]).then(function(){
        console.log(videoData);
    });
</script>

答案 3 :(得分:0)

您可以使用promise来解决此问题。来自documentation

  

Promise接口不一定代表值的代理   在创作时就知道了。它允许您将处理程序关联到   异步操作最终成功或失败。这让我们   异步方法返回类似于同步方法的值:相反   对于最终值,异步方法返回一个promise   在将来的某个时刻有价值。

阅读 this 并开始工作。我们将使用jquery when 函数。

$.when(searchYTVideos("test1",0),  searchVideo("test2", 0)).done(function(data){
  // your logic
});

我的代码只是示例,在您的情况下,promise方法非常强大且有用。它有助于避免spaggeti代码。

还有非常good explanation的例子

相关问题