【问题标题】:Asynchronous javascript with 2 callbacks - how?带有 2 个回调的异步 javascript - 如何?
【发布时间】:2015-05-19 20:14:34
【问题描述】:

我需要代码像这样流动:从 calcRoute 获取值(谷歌地图距离)-> 添加到数组(?)/添加到输出字符串,直到它遍历所有值。然后追加到列表视图。

var myArray = [];
$.get( "http://www.url.com/info.php", function( data ) {

        var output = "";
        var imgsrc = "";

         obj = jQuery.parseJSON(data);


        for (i = 0; i < obj.length; i++) 
            { 

                store=obj[i].store;

            for (j = 0; j < obj[i].products.length; j++) 
                { 
                    productname= obj[i].products[j].productname;
                    price=obj[i].products[j].price;

                    calcRoute(function(returnValue) {

                        myArray.push(returnValue);
                        console.log("Inside callback : " + flowcounter++);
                        console.log("Inside callback (Array): " + myArray);
                    }); 

                    console.log("Array has now (J-loop) : " + myArray);
                    console.log("Flowcounter has now (J-loop) : " + flowcounter++);
                    output+='<li> <img style="margin-left: 8px" width="80" height="80" alt="sample" src="img/logo.png" align="left"/> <h3>'+ productname+' '+price+'</h3><p>Ca:'+ myArray[i] +' km.</p> </li>';                 
                }

            }


        console.log("Append to list (Counter) : " + flowcounter++);
        console.log("Appen to list(Array): " + myArray);
        $("#prodlist").append(output).listview().listview('refresh');

            });

但现在它是这样的:J-loop -> append to listview -> calcRoute。 所以在执行下一件事之前它没有值。这里的问题显然是我需要获取一个值,将其放入输出中,当它们都完成后,放入 prodlist-append。 这是 calcRoute 代码:

        function calcRoute(callback) {

        var start = new google.maps.LatLng(55.613520,12.534539);
        var end = new google.maps.LatLng(55.713520,12.534539);

    var request = {
          origin: start,
          destination: end,
          travelMode: google.maps.TravelMode["DRIVING"]
      };
      directionsService.route(request, function(response, status) {
          if (status == google.maps.DirectionsStatus.OK) {
              directionsDisplay.setDirections(response);
          }
          var totalDistance = 0;
          var legs = response.routes[0].legs;
          for(var i=0; i<legs.length; ++i) {
             totalDistance += legs[i].distance.value;
          }
          totalDistance = totalDistance / 1000;
         totalDistance = totalDistance.toFixed(1);
         myArray.push(totalDistance);
         callback(totalDistance);
     });
    };

也添加了 logcat:

任何帮助表示赞赏。

【问题讨论】:

标签: javascript asynchronous callback


【解决方案1】:

Javascript Promises

它们允许您链接异步操作,例如:

doThing1().then(doThing2()).then(doThing3());

或者可能更适合您的目的,Promise.all 将等到所有操作完成后再进行下一步操作:

Promise.all([
    doThing1(),
    doThing2(),
    doThing3()
]).then(addToList(results));

Here's a jsfiddle 概述了您可能在这里做的事情。我不知道你到底想做什么,但希望它足以让你感动。

Javascript:

var storeData = [
    {
        name: 'Store 1',
        location: {
            lat: 55.613520,
            lng: 12.534539
        },
        products: [
            {
                productname: "Product 1",
                price: 1.10
            },
            {
                productname: "Product 2",
                price: 2.20
            }
        ]
    },
    {
        name: 'Store 2',
        location: {
            lat: 55.613520,
            lng: 12.634539
        },
        products: [
            {
                productname: "Product 1.1",
                price: 1.11
            }
        ]
    }
];

// wraps a jquery ajax request for store data in a Promise
function getStores() {
    return new Promise(function(fulfill, reject) {

        // this is a jsfiddle ajax request
        // that just returns the json you send it (storeData).
        $.post( '/echo/json/', {
            json: JSON.stringify(storeData),
            delay: 1
        })
        .done(function(result) {
            return fulfill(result);    
        })
        .fail(function(reason) {
            return reject(reason);
        });
    });
}

function calcRoute(store) {
    return new Promise(function(fulfill, reject) {
        // call google here. faking it for the fiddle.
        return fulfill({
            result: 'Fake route result for store ' + store.name
        });
    });
}

function getRoutes(stores) {
    var promises = [];
    for (var i = 0; i < stores.length; i++) {
        promises.push(calcRoute(stores[i]));
    }
    return Promise.all(promises);
}

function updateDisplay(routes) {
    var list = document.getElementById('list');
    for (var i = 0; i < routes.length; i++ ) {
        console.log(routes[i].result);
        $(list).append('<li>' + routes[i].result + '</li>');
    }
}

function go() {
    return getStores()
    .then(getRoutes)
    .then(updateDisplay)
    .catch(function(reason) {
        console.error('Error %O', reason);
    });
}

$.ready(go());

【讨论】:

  • 请记住,这种结构要求每个 doThingx() 函数返回一个在异步操作完成时解析的承诺。
  • 您能否引导我了解如何使用我的代码执行此操作?对我来说似乎根本不起作用。
  • @Rad 更新了我的答案以包含示例代码/jsfiddle。
  • 另外请记住,您可能需要在某些浏览器中为 Promises 使用 polyfill,尤其是 IE
【解决方案2】:

您可以使用嵌套回调,或者在某些框架中,您可以使用 Promise 链接 .then 或 .success。这是一篇关于扁平化嵌套回调以避免“回调地狱”的有趣文章http://solutionoptimist.com/2013/12/27/javascript-promise-chains-2/

【讨论】:

    猜你喜欢
    • 2018-12-10
    • 2018-04-29
    • 1970-01-01
    • 2016-09-02
    • 2016-10-24
    • 2013-09-12
    • 1970-01-01
    • 2012-01-02
    • 1970-01-01
    相关资源
    最近更新 更多