【问题标题】:Making sense of asynchronous javascript (google maps)理解异步 javascript(谷歌地图)
【发布时间】:2014-06-01 14:44:40
【问题描述】:

我下面的答案有一个工作代码示例和一个解释


我正在尝试通过在 Google 地图 API 的帮助下创建旅行销售员算法来了解异步编程。

这是它的工作原理:

  1. 我们有一个地址字符串列表addresses
  2. 对于地址 [i] 和 [j] 的每个组合,我们使用 google 计算距离 方向服务,我们将其存储在 Javascript 对象 (distanceTable) 中。
  3. tspSolver 应该在我们获得所有距离后运行(尚未实现)。

我的天真代码如下。如您所见,有几个问题,所有这些都与回调有关:

我将directionResults 作为回调传递给方向服务。它正确计算了距离,但由于我不再在循环内构造距离表,因此我无法正确存储结果。我注释掉了应该存储它的部分,但这显然只在循环内有效。

我将tspSolver 作为allDistances 的回调传递给我。但是我注意到它在距离由directionResults 计算之前执行。我的猜测是我必须做某种形式的回调嵌套?

谁能帮助我理解这一点。

gMap.directionsService = new google.maps.DirectionsService();

var addresses = ['Dam, Amsterdam','Spui, Amsterdam','Middenweg, Amsterdam'];
var distanceTable = {};
//all combinations of addresses with distances, for use in TSP algorithm
//{
//  addressA {
//    addressB: 2000
//    addressC: 2500
//  }
//  addressB {
//    addressC: 1800
//  }


function tspSolver(distanceTable) {
  console.log('Distances are there, now for some clever TSP algorithm')
  //this should only be executed after the distances are returned.
}

function allDistances(addresses, callback) {
  for(var i=0; i<addresses.length; ++i) {
    distanceTable[addresses[i]] = {};
    for(var j=i+1; j<addresses.length; ++j) {
      // Compose request for every pair of addresses (one way)
      var request = {
        origin: addresses[i],
        destination: addresses[j],
        travelMode: 'DRIVING'
      };
      console.log(request);
      gMap.directionsService.route(request, directionResults);
    }
  }
  callback(distanceTable)
}


function directionResults(result, status) {
  console.log("Receiving request for route");
  console.log(result);
  if (status == google.maps.DirectionsStatus.OK) {
    var totalDistance = 0;
    var legs = result.routes[0].legs;
    for(var i=0; i<legs.length; ++i) {
      totalDistance += legs[i].distance.value;
    }
    console.log(totalDistance);
    // I really want to add it to the distanceTable...
    //distanceTable[addresses[i]][addresses[j]] = totalDistance;
  }
}


//call function to start solving
function executeTSP() {
  allDistances(addresses, tspSolver);
}

【问题讨论】:

    标签: javascript google-maps asynchronous callback


    【解决方案1】:

    我假设您需要通过请求传递回调

    回调是异步编程时继续执行的方式。

    伪例子:

    function doAcync(callback)
    {
     //gets result
     callback(result);
    }
    
    function one()
    {
      doAcync(two);
    }
    
    function two(result)
    {
      doAcync(three);
    }
    
    function three(result)
    {
      // continue with your live
    }
    

    【讨论】:

    • 那么传递给函数二和三的“结果”是什么?抱歉,但我无法理解这个问题。
    • 大多数人一开始都不担心。结果是从异步调用中检索到的,这是一种约定,如果您传递回调并且您传递回调的函数具有返回值,那么回调函数将使用该返回值调用。
    • 我认为您的模式将帮助我解决我的第二个问题(执行顺序)。我不相信它会帮助我将结果写入 distanceTable...
    • 我用工作代码添加了另一个答案。我认为它不漂亮,但它完成了工作。我不得不承认我没有使用您的模式,但感谢您的帮助。
    【解决方案2】:

    我的第一个问题的解决方案在于“循环内的闭包”。我正在用一个计数器跟踪我的循环(在我的情况下是 2 个计数器)。到异步函数/闭包执行时,循环已经完成。

    这将阻止从闭包内访问循环计数器的所有尝试:您将始终获得最大数量。

    我选择的解决方案是将闭包包装在另一个函数中:所谓的“匿名包装器”。这个包装器包含一个不受循环影响的引用。

    可以在这里找到一些更好的解释: Mutable variable is accessible from closure. How can I fix this? 和这里: http://bonsaiden.github.io/JavaScript-Garden/#function.closures

    为了解决第二个问题(执行顺序),我在回调中进行了回调。一些公认的丑陋代码会跟踪回调仅在最后一次迭代时调用。我相信有更优雅的方法来处理这个问题,但现在它可以工作:

    var directionsService;
    
    function initialize() {
      directionsService = new google.maps.DirectionsService();
    }
    
    var addresses = ['Dam, Amsterdam','Spui, Amsterdam','Middenweg, Amsterdam'];
    var distanceTable = {};
    //all combinations of addresses with distances, for use in TSP algorithm
    //{
    //  addressA {
    //    addressB: 2000
    //    addressC: 2500
    //  }
    //  addressB {
    //    addressC: 1800
    //  }
    
    
    function tspSolver(distances) {
      //this function is called as a callback from allDistances
      for(var i=0; i<addresses.length; ++i) {
        for(var j=i+1; j<addresses.length; ++j) {
          console.log(addresses[i]+' to '+addresses[j]+': '+distances[addresses[i]][addresses[j]])
        }
      }
    }
    
    function allDistances(addresses, callback) {
      for(var i=0; i<addresses.length; ++i) {
        distanceTable[addresses[i]] = {};
        for(var j=i+1; j<addresses.length; ++j) {
          var request = {
            origin: addresses[i],
            destination: addresses[j],
            travelMode: 'DRIVING'
          };
          console.log(request);
          //anonymous wrapper around closure to preserve the loop counters: i,j -> e,f
          (function(e,f) {directionsService.route(request, function(result,status) {
              if (status == google.maps.DirectionsStatus.OK) {
                //calculate totalDistance as sum of the legs and store the result
                var totalDistance = 0;
                var legs = result.routes[0].legs;
                for(var x=0; x<legs.length; ++x) {
                  totalDistance += legs[x].distance.value;
                }
                distanceTable[addresses[e]][addresses[f]] = totalDistance;
              }
            //trigger the callback on the last iteration only
            if (e+2 == addresses.length)
              {
                callback(distanceTable)
              }
            });
          })(i,j);
          //end of wrapper
        }
      }
    }
    
    function executeTSP(){
      allDistances(addresses, tspSolver)
    }
    

    【讨论】:

      猜你喜欢
      • 2016-03-31
      • 1970-01-01
      • 1970-01-01
      • 2014-09-29
      • 1970-01-01
      • 2014-07-13
      • 2012-07-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多