-2

I am trying to make one function running after another one, but and complete are running with my called function at the same time.

the console is printing out 2, 1, and supposed to be 1 is the first, how to make complete function waiting my fetchingFunction done to execute, please help

var loopControl = 0;

$('[data-toggle=tab]').on('show.bs.tab', function(e) {

  if (loopControl == 0) {
    e.preventDefault();

    var ref = $(this).attr('href').replace('#', '');
    loopControl = 1;

    $.ajax({
      url: fetchingFunction(),
      success: function() {
       
      },
      complete: function() {
         fakeFunction2();
         $('.' + ref + '_tab').click();
      }
    });
  } else {

    loopControl = 0;
  }
});

function fetchingFunction() {
  setTimeout(function() {
    console.log("1");
  }, 2000);

}

function fakeFunction2() {
    console.log("2")
}
<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>

View on JSFiddle

FJ Shen
  • 41
  • 2
  • 5
  • 2
    `fetchingFunction`, ignoring the setTimeout inside of it, doesn't return a string to be used for the `url`. Your scripting is very confusing. – Taplar Jun 01 '18 at 16:36
  • 2
    Don't use `async: false,`. – Bergi Jun 01 '18 at 16:37
  • 1
    To have a one function run after another, either both functions have to not perform asynchronous actions, or the first should return a promise/deferred and the second should be called from a callback attached to the promise/deferred to be executed upon its resolution. – Taplar Jun 01 '18 at 16:39
  • @Taplar thanks for your quick responding, because my actuall fetching function is very time consuming, I want to make sure the tab content is loaded after my fetching function is done, so that's why i set a waiting time. – FJ Shen Jun 01 '18 at 16:40
  • It would be helpful if you gave us a slimmed down version of your actual logic. As you have it, as you can see, you are going to get questions about how you constructed the question, versus towards your actual existing logic. – Taplar Jun 01 '18 at 16:42
  • @Taplar it is updated, I just want my complete function running after my called function finish, not on the same time. thanks – FJ Shen Jun 01 '18 at 16:50
  • It seems that `setTimeout` is delaying the output from `fetchingFunction()`. So you see the output from `fakeFunction2()` first, even though it's called after `fetchingFunction()`. – showdev Jun 01 '18 at 16:52

1 Answers1

1

I modified your fetchingFunction to return a promise, so it will act as if you were making an asynchronous call in there.

First, you call fetchingFunction(), which is returning a promise.

Second, you attach a callback to that promise so that it will execute after the promise has finished, accepting in the value that was returned.

var loopControl = 0;

$('[data-toggle=tab]').on('show.bs.tab', function(e) {
  if (loopControl != 0) return;

  loopControl = 1;
  e.preventDefault();

  var ref = this.href.replace('#', '');
  
  fetchingFunction().then(function(url){
    console.log(url);

    $.ajax({
      url: url,
      complete: function() {
         fakeFunction2();
         //$('.' + ref + '_tab').click();
         loopControl = 0; //processing is done, reset the lock
      }
    });
  });
});

function fetchingFunction() {
  return new Promise(function(resolve, reject){
    setTimeout(function() {
      console.log("1");
      resolve('https://stackoverflow.com/');
    }, 2000);
  });
}

function fakeFunction2() {
    console.log("2");
}
<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>
Taplar
  • 24,788
  • 4
  • 22
  • 35
  • Watch out for [the explicit promise construction antipattern](https://stackoverflow.com/q/23803743)... – Heretic Monkey Jun 01 '18 at 18:07
  • @MikeMcCaughan I'm not suggesting they use new Promise(). I used it simply to simulate a fake ajax request. – Taplar Jun 01 '18 at 18:08
  • Sure, but the more the pattern is seen "in the wild", the more I see people throwing it into code I get to review. Just a warning for those coming across the answer and thinking it's a good way to make an asynchronous function, that's all. – Heretic Monkey Jun 01 '18 at 18:11