Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在循环中调用时如何显示JS异步结果?_Javascript_Asynchronous_Formatting_Synchronous - Fatal编程技术网

Javascript 在循环中调用时如何显示JS异步结果?

Javascript 在循环中调用时如何显示JS异步结果?,javascript,asynchronous,formatting,synchronous,Javascript,Asynchronous,Formatting,Synchronous,我正在做一个个人项目,我被困在一个“基本”的同步/异步Javascript问题上 总之,我调用一个异步API,然后在屏幕上显示结果。 格式化后的预期结果是:“距离Y X公里处”,其中X是从API计算并正确返回的,Y是位置的名称(未正确显示) 这是我的代码,为了更好地理解,这里有一些注释: //loadedLandmarks.length is **always** between 1 and 3. No exception. //In this sample, let's say we have

我正在做一个个人项目,我被困在一个“基本”的同步/异步Javascript问题上

总之,我调用一个异步API,然后在屏幕上显示结果。
格式化后的预期结果是:“距离Y X公里处”,其中X是从API计算并正确返回的,Y是位置的名称(未正确显示)

这是我的代码,为了更好地理解,这里有一些注释:

//loadedLandmarks.length is **always** between 1 and 3. No exception.
//In this sample, let's say we have 3 items in loadedLandmarks
for(var i = 0 ; i < loadedLandmarks.length ; i++)
{
    var currentLandmarkName = loadedLandmarks[i].customInfo.Name;
    landmarksName.push(loadedLandmarks[i].customInfo.Name);

    //landmarkName contains the good names, for example : "My school", "My home", "My favorite nightclub" (here after 3 pass on the loop)
    console.log(landmarksName);

    //DisplayDistanceFromLandmarks is my method which calls the asynchronous API. It seems OK.
    DisplayDistanceFromLandmarks(pos, i).then(function(response) {
        //The response variable contains correct informations from the API
        var origins = response.originAddresses;
        var destinations = response.destinationAddresses;
        var results = response.rows[0].elements;

        //I explain this line below
        console.log(loadedLandmarks)

        //Then I'm formatting the result to display it on screen (I only paste here the interesting part)
        distances += "<br />At " + results[0].distance.value + "kms from" + currentLandmarkName;

        return distances;
}).done( /*some other things*/ );
//loadedLandmarks.length始终**在1和3之间。也不例外。
//在这个示例中,假设我们在loadedLandmarks中有3项
对于(变量i=0;i在“+结果[0]。距离.value+”公里距离“+currentLandmarkName;
返回距离;
}).完成(/*一些其他事情*/);
显示的结果如下:

距离[在此插入最后一个currentLandmarkName]5公里处
距离[在此插入最后一个currentLandmarkName]8.5公里处
距离[在此插入最后一个currentLandmarkName]0.2公里处

鉴于它应该是:

距离[在此插入第一个currentLandmarkName]5公里处
距离[在此插入第二个currentLandmarkName]8.5公里处
距离[在此插入第三个currentLandmarkName]0.2公里处

我不明白的是,当我编写
console.log(loadedLandmarks)
时,数组的内容是正确的,带有
loadedLandmarks[0]。Name
=第一个名字,
loadedLandmarks[1]。Name
=第二个名字等等。 但是,
i
始终等于3,
currentLandmarkName
始终等于最后一个LandmarkName。
看起来它们被覆盖了,我不明白为什么



我对JS和异步问题非常陌生,有人能解释我为什么会遇到这种行为,以及,非常重要的,如何纠正它吗?

这个方法
displaydestancefromlandmarks
是异步的,这意味着它不会阻止其余的代码执行。所以当你在ca中形成html字符串
distance
时我也这么说:

distances += "<br />At " + results[0].distance.value + "kms from" + currentLandmarkName;
我觉得你可以做两件事:

  • 将变量
    currentLandmarkName
    传递到
    DisplayDistanceFromLandmarks
    方法中,从而将其纳入范围
  • 您还可以尝试使用while循环,并仅在回调内递增计数器,即变量
    i
    。这样,您就强制异步行为是同步的。因此,只有在解析承诺并评估回调后,才会进行下一次循环迭代
  • 我遇到了一篇非常好的文章,解释了javascript的异步行为和闭包的概念。你可能想读一读

    希望它能让你朝着正确的方向开始。干杯!

    Hy, 这是JavaScript和闭包的典型问题

    在传递给
    DisplayDistanceFromLandmarks(pos,i)的函数中,然后()
    使用变量
    currentLandmarkName
    ,这会给您带来一些麻烦

    该变量不是在该函数内部定义的,而是在该函数外部的
    循环中定义的:

    for(var i = 0 ; i < loadedLandmarks.length ; i++)
    {
        var currentLandmarkName = loadedLandmarks[i].customInfo.Name;
        ...
    
    i
    等于
    加载的地标。长度-1

    因此,当调用
    then
    函数时,它会尝试访问始终等于最后一个元素的
    currentLandmarkName
    引用:

     loadedLandmarks[loadedLandmarks.length-1].customInfo.Name;
    
    因此,您总是会得到
    [在此处插入最后一个currentLandmarkName]

    var i=0;
    
    var i = 0;
    var DisplayDistance = function () {
            var currentLandmarkName = loadedLandmarks[i].customInfo.Name;
            landmarksName.push(loadedLandmarks[i].customInfo.Name);
    
            //landmarkName contains the good names, for example : "My school", "My home", "My favorite nightclub" (here after 3 pass on the loop)
            console.log(landmarksName);
    
            //DisplayDistanceFromLandmarks is my method which calls the asynchronous API. It seems OK.
            DisplayDistanceFromLandmarks(pos, i).then(function(response) {
                //The response variable contains correct informations from the API
                var origins = response.originAddresses;
                var destinations = response.destinationAddresses;
                var results = response.rows[0].elements;
    
                //I explain this line below
                console.log(loadedLandmarks)
    
                //Then I'm formatting the result to display it on screen (I only paste here the interesting part)
                distances += "<br />At " + results[0].distance.value + "kms from" + currentLandmarkName;
    
                i++;
                if (i < loadedLandmarks.length) {
                    DisplayDistance();
                }
    
                return distances;
        }).done( /*some other things*/ );
    }
    DisplayDistance();
    
    var DisplayDistance=函数(){ var currentLandmarkName=loadedLandmarks[i].customInfo.Name; LandmarkName.push(loadedLandmarks[i].customInfo.Name); //landmarkName包含好名字,例如:“我的学校”、“我的家”、“我最喜欢的夜总会”(在循环3次之后) console.log(landmarksName); //DisplayDistanceFromLandmarks是我调用异步API的方法,看起来还可以。 显示与地标的距离(位置,i)。然后(功能(响应){ //响应变量包含来自API的正确信息 var origins=response.originAddresses; var destinations=response.destinationaddress; var results=response.rows[0]。元素; //我在下面解释这一行 console.log(加载的地标) //然后我将格式化结果以在屏幕上显示它(我只在这里粘贴有趣的部分) 距离+=“
    在“+结果[0]。距离.value+”公里距离“+currentLandmarkName; i++; 如果(i<加载的地标长度){ 显示距离(); } 返回距离; }).完成(/*一些其他事情*/); } 显示距离();
    我只是复制/粘贴了你建议的修改,效果非常好,非常感谢!!用你的代码进行一些解释可能会更好,但我会尝试用其他答案来理解。再次感谢Hanks的解释
     loadedLandmarks[loadedLandmarks.length-1].customInfo.Name;
    
    var i = 0;
    var DisplayDistance = function () {
            var currentLandmarkName = loadedLandmarks[i].customInfo.Name;
            landmarksName.push(loadedLandmarks[i].customInfo.Name);
    
            //landmarkName contains the good names, for example : "My school", "My home", "My favorite nightclub" (here after 3 pass on the loop)
            console.log(landmarksName);
    
            //DisplayDistanceFromLandmarks is my method which calls the asynchronous API. It seems OK.
            DisplayDistanceFromLandmarks(pos, i).then(function(response) {
                //The response variable contains correct informations from the API
                var origins = response.originAddresses;
                var destinations = response.destinationAddresses;
                var results = response.rows[0].elements;
    
                //I explain this line below
                console.log(loadedLandmarks)
    
                //Then I'm formatting the result to display it on screen (I only paste here the interesting part)
                distances += "<br />At " + results[0].distance.value + "kms from" + currentLandmarkName;
    
                i++;
                if (i < loadedLandmarks.length) {
                    DisplayDistance();
                }
    
                return distances;
        }).done( /*some other things*/ );
    }
    DisplayDistance();