JavaScript / JQuery:避免嵌套异步函数/匿名回调函数的最佳方法

时间:2016-01-07 10:38:12

标签: javascript asynchronous

我的JavaScript代码包含很多异步函数。例如,我正在使用D3.JS来读取CSV文件,并且我正在连接到Google Maps API以查找两个地址之间的行车路线。

我在StackOverflow上使用this answer等待异步函数完成(以避免返回值为undefined的变量)。但是,因为我有很多异步函数,所以我有很多嵌套的匿名回调函数:

    carDirections(from, to).done(function(car) {
        transitDirections(from, to).done(function(train) {
        // carDirections and trainDirections have similar anonymous callback functions.

    function carDirections(from, to) {
        var dfd = $.Deferred();

        var directionsService = new google.maps.DirectionsService;

        directionsService.route({
            origin: from,
            destination: to,
            travelMode: google.maps.TravelMode.DRIVING
        }, function(response, status) {
            if (status === google.maps.DirectionsStatus.OK) {
                dfd.resolve(response.routes[0].legs[0]);
            }
        });

        return dfd.promise();
    }
    // Similar code for transitDirections.

这会产生doneDeferred函数的意大利面,这使得代码很难理解。有没有正确的方法来解决这个问题?例如,我可以重新编程我的Google Maps函数以使它们同步,还是有另一种(更简单的方法)只在前一个函数返回变量时才继续执行代码?

2 个答案:

答案 0 :(得分:1)

您可能希望read up更多关于Promise s的主题。您可以链接异步操作,如

asyncOp1()
  .then(result1 => asyncOp2(result1))
  .then(result2 => asyncOp3(result2))
  .then(result3 => Promise.all(asyncOp4(result3), asyncOp5(result3)))
  .catch(error => { /* deal with an error */ })
  // ...

如果所有操作都返回Promise(这有助于避免嵌套)。 (Transpile上述伪代码到ES5,polyfill Promise,如果需要的话。)

如果您正在寻找完全处理复杂异步代码的不同方法,请查看RxJS ...如果您这样做,我不承担任何责任:)

答案 1 :(得分:0)

据我所知,trainDirections不需要从carDirections获得任何响应,您只需要在所有操作完成后触发回调?

您可以使用延迟对象。

var deferredObj1 = $.Deferred(),
    deferredObj2 = $.Deferred();

$.when(deferredObj1,deferredObj2).done(function(){
    console.log("They are both done!");
});

// inside the Event1 handler:
deferredObj1.resolve();

// inside the Event2 handler:
deferredObj2.resolve();
  

jQuery 1.5中引入的Deferred对象是一个可链接的实用程序   通过调用jQuery.Deferred()方法创建的对象。它可以   将多个回调注册到回调队列中,调用回调   队列,并中继任何同步或成功或失败状态   异步功能。