2017-02-10 153 views
1

我写了一个小程序来帮助我理解如何在jQuery中执行嵌套的异步承诺。嵌套异步jquery承诺

我想按顺序调用两个任务。第一项任务有两个子任务也是按顺序调用的。就这样。

虽然这有效,但我怀疑这是否是使用承诺的最佳方式。不得不为每个任务创建一个新的延迟感觉就像代码味道给我。例如,传递单个延迟对象并仅使用该对象会更好吗?谢谢!

https://plnkr.co/edit/dyFFqqZhCVuhBYCuWjzm?p=preview

doTasks().then(function(arg) { 
    console.log(arg) 
}) 

function doTasks() { 
    var d = $.Deferred(); 
    task1().then(function(arg) { 
     console.log(arg) 
     task2().then(function(arg) { 
      console.log(arg) 
      d.resolve('all tasks are done') 
     }) 
    }) 
    return d.promise(); 
} 

function task1() { 
    var d = $.Deferred(); 

    console.log("starting task1...") 

    setTimeout(function() { 
     task1A().then(function() { 
      task1B().then(function() { 
       d.resolve('task1 is done') 
      }) 
     }) 
    }, 10); 

    return d.promise(); 
} 

function task1A() { 
    var d = $.Deferred(); 
    console.log("starting task1A...") 
    setTimeout(function() { 
     console.log(" resolving task1A...") 
     d.resolve(); 
    }, 1000); 
    return d.promise(); 
} 

function task1B() { 
    var d = $.Deferred(); 
    console.log("starting task1B...") 
    setTimeout(function() { 
     console.log(" resolving task1B...") 
     d.resolve(); 
    }, 1000); 
    return d.promise(); 
} 

function task2() { 
    var d = $.Deferred(); 
    console.log("starting task2...") 

    setTimeout(function() { 
     d.resolve('task2 is done'); 
    }, 1000); 
    return d.promise() 
} 

回答

1

是的,这是一个有点臭创造了很多不必要的deferreds的。

您不需要为您的ajax操作创建任何延迟。如果您从.then()处理程序中返回承诺,它将自动链接到之前的承诺(从而对其进行排序),并且所有jquery ajax调用都已返回承诺。所以你不需要为ajax操作创建任何你自己的承诺。而且,您可以链接而不是嵌套,以便对您的操作进行排序。

事实上,当您不需要时创建延迟或承诺被称为promise anti-pattern。您想要使用并返回已经创建的承诺,而不是创建新承诺。而且,如果可能的话,你想链接你的承诺而不是筑巢。

下面是如何在可运行代码段中执行此操作,而无需创建一个延迟除了一个地方以将setTimeout()包装在承诺中。显然,如果你为它们创建了一个可重用的函数,你可以使用更少的代码来处理所有的任务,但是我假设这些只是真正的异步操作的占位符,所以我会保留原样(除了使用共享delay()函数)。

doTasks().then(function(arg) { 
 
    console.log("everything done"); 
 
}) 
 

 
function doTasks() { 
 
    return task1().then(function(arg) { 
 
     console.log(arg); 
 
     return task2().then(function(arg) { 
 
      console.log(arg) 
 
      return arg; 
 
     }) 
 
    }) 
 
} 
 

 
// make promise version of setTimeout() in one central place 
 
// that can then be used elsewhere 
 
function delay(t) { 
 
    return $.Deferred(function(def) { 
 
     setTimeout(function() { 
 
      def.resolve(); 
 
     }, t); 
 
    }).promise(); 
 
} 
 

 
function task1() { 
 
    console.log("starting task1...") 
 
    return delay(10).then(function() { 
 
     return task1A(); 
 
    }).then(function() { 
 
     return task1B(); 
 
    }); 
 
} 
 

 
function task1A() { 
 
    console.log("starting task1A...") 
 
    return delay(1000).then(function() { 
 
     console.log(" resolving task1A...") 
 
     return "done task1A"; 
 
    }); 
 
} 
 

 
function task1B() { 
 
    console.log("starting task1B...") 
 
    return delay(1000).then(function() { 
 
     console.log(" resolving task1B...") 
 
     return "done task1B"; 
 
    }); 
 
} 
 

 
function task2() { 
 
    console.log("starting task2...") 
 
    return delay(1000).then(function() { 
 
     console.log(" task2 is done") 
 
     return "done task2"; 
 
    }); 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

2

你不应该巢你的承诺。这个想法是,你可以通过在第一个回调中返回一个值,并链接下一个then,在它自己的回调中执行下一步......等等。

正如你在几个地方使用一个定时器来解决一个承诺,你可以创建一个函数来返回这个基于毫秒数的promise。

你甚至可以创建一个函数来输出一些东西,然后再次返回一个承诺。

这将让您链一大堆在一起:

doTasks().then(say.bind(null, 'all done')); 
 

 
function say(msg) { 
 
    console.log(msg); 
 
    return $.Deferred().resolve(msg).promise(); 
 
} 
 

 
function doTasks() { 
 
    return task1().then(task2); 
 
} 
 

 
function delay(ms) { // one function for delaying as a promise 
 
    var d = $.Deferred(); 
 
    setTimeout(d.resolve.bind(null, ' delay completed'), ms); 
 
    return say('starting delay of ' + ms + ' milliseconds...') 
 
     .then(d.promise).then(say); 
 
} 
 

 
function task1() { 
 
    return say('starting task1...').then(delay.bind(null, 10)) 
 
     .then(task1A).then(task1B).then(say.bind(null, 'task1 done')); 
 
} 
 

 
function task1A() { 
 
    return say('starting task1A...').then(delay.bind(null, 1000)) 
 
     .then(say.bind(null, ' resolving task1A...')); 
 
} 
 

 
function task1B() { 
 
    return say('starting task1B...').then(delay.bind(null, 1000)) 
 
     .then(say.bind(null, ' resolving task1B...')); 
 
} 
 

 
function task2() { 
 
    return say('starting task2...').then(delay.bind(null, 1000)) 
 
     .then(say.bind(null, 'task2 done')); 
 
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>

+0

你为什么会提供这样的回答时,我的回答(20分钟前)几乎提供了所有相同的信息? – jfriend00