如何使complete函数等待fetchingFunction执行完毕后再执行?
解决异步函数执行顺序问题:让后续操作等待异步任务完成
你现在遇到的情况是fetchingFunction里的setTimeout是异步操作,而你原来的代码没做任何等待处理,导致complete回调直接先跑了,控制台先输出2再输出1。我帮你捋捋问题根源,然后给你调整好代码:
问题出在哪?
fetchingFunction是异步逻辑,但你直接把它的返回值传给了$.ajax的url参数——可这个函数根本没返回有效URL,里面的setTimeout是完全独立的异步任务,和AJAX请求半毛钱关系都没有。- AJAX因为拿到的
url是undefined,会立刻报错并进入complete回调,自然就先执行fakeFunction2打印2了,而setTimeout要等2秒才会打印1。
解决方案:用Promise控制异步顺序
我们需要把fetchingFunction改成返回Promise的形式,这样就能用async/await或者Promise.then()来强制后续操作等它完成后再执行。
修改后的完整代码
HTML部分(保持不变)
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.1.0/bootstrap.min.js"></script> <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet" /> <ul class="nav nav-tabs"> <li><a class='aaa_tab' href="#aaa" data-toggle="tab">AAA</a></li> <li><a class='bbb_tab' href="#bbb" data-toggle="tab">BBB</a></li> <li><a class='ccc_tab' href="#ccc" data-toggle="tab">CCC</a></li> </ul> <div class="tab-content" id="tabs"> <div class="tab-pane" id="aaa">...Content1...</div> <div class="tab-pane" id="bbb">...Content2...</div> <div class="tab-pane" id="ccc">...Content3...</div> </div>
JavaScript部分(核心逻辑修改)
var loopControl = 0; // 把fetchingFunction改成返回Promise的异步函数 function fetchingFunction() { return new Promise((resolve) => { setTimeout(function() { console.log("1"); resolve(); // 异步任务完成后,触发resolve通知外部可以继续执行后续逻辑 }, 2000); }); } function fakeFunction2() { console.log("2"); } $('[data-toggle=tab]').on('show.bs.tab', async function(e) { if (loopControl == 0) { e.preventDefault(); var ref = $(this).attr('href').replace('#', ''); loopControl = 1; // 等待fetchingFunction的异步任务完成 await fetchingFunction(); // 异步任务完成后,再执行后续操作 fakeFunction2(); $('.' + ref + '_tab').click(); loopControl = 0; } else { loopControl = 0; } });
额外补充:如果AJAX有实际用途
如果你原来的AJAX是要请求真实接口的,那可以把AJAX放在fetchingFunction完成后执行,比如让fetchingFunction返回接口URL:
function fetchingFunction() { return new Promise((resolve) => { setTimeout(function() { console.log("1"); resolve('你的真实接口URL'); // 返回接口地址 }, 2000); }); } // 事件处理里的逻辑调整 $('[data-toggle=tab]').on('show.bs.tab', function(e) { if (loopControl == 0) { e.preventDefault(); var ref = $(this).attr('href').replace('#', ''); loopControl = 1; fetchingFunction().then((url) => { $.ajax({ url: url, success: function() { // 接口请求成功后的自定义逻辑 }, complete: function() { fakeFunction2(); $('.' + ref + '_tab').click(); loopControl = 0; } }); }); } else { loopControl = 0; } });
这样修改后,控制台会先输出1,等待2秒异步任务完成后再输出2,完全符合你的预期。
内容的提问来源于stack exchange,提问作者FJ Shen
相关产品推荐
相关产品推荐

