2

I'm having the hardest time wrapping my head around javascript callbacks for some reason and it's causing me a lot of headaches. I have three functions that I'm trying to use to parse some data from a website like so—

function parseText() {
    //this finds a bunch of DOM elements, grabs the innerHTML from each and stores
    //it in an array
}

function scrollToTop() {
    //this scrolls to the top of the window where I'm getting text from,
    //which causes the window to load more DOM elements to parse
}

function removeOldElements() {
    //this removes the already-parsed DOM elements from the DOM
}

and I've been calling it like this.. which I now realise is a completely horrid method of doing things because as soon as I switch tabs Chrome completely messes with setTimeout and setInterval timings and causes a lot of errors..

function doEverything() {
    parseText();
    setTimeout(scrollToTop, 2000);
    setTimeout(removeOldElements, 4000);
}

setInterval(doEverything, 5000); 
//this loops it every 5 seconds so I can just run it in a separate tab
//while I continue to work on other things

This works kind of.. but any pause or interruption in setInterval breaks the code, and I know I should be using callbacks for this kind of thing in order to call one once the first one is done executing, but I just can't seem to get it to work.

I've been reading about callbacks and don't really understand what the format is supposed to be.. I've tried something like this:

function parseText(callback) {
}

function scrollToTop(callback) {
}

function removeOldElements() {
}

function doEverything() {
    parseText(
        scrollToTop(
            removeOldElements
        )
    )
}

setInterval(doEverything, 5000);

But this only seems to be calling scrollToTop and then parseText twice.. and doesn't call the third function at all! What the heck! Now I'm really confused..

Could anyone assist? I'm sure I'm doing something very basic completely wrong here..

shan
  • 3,035
  • 5
  • 34
  • 50
  • I think it is more like this one: http://stackoverflow.com/questions/37024934/how-to-avoid-multiple-variable-re-declarations-on-function-outputs-in-javascript – Quentin Roy May 05 '16 at 02:05
  • What exactly do you mean by "*which causes the window to load more DOM elements to parse*"? Is that some kind of asynchronous action? – Bergi May 05 '16 at 02:17
  • Yeah, the site I'm trying to parse data from loads more DOM elements when you scroll to the top of a container div, which I.. think? Means it's asynchronous.. I need to wait for that to be done before calling removeOldElements! – shan May 05 '16 at 02:29

3 Answers3

0

You're talking about callbacks, but I don't see anything explicitly async about your code. You need to differentiate between two things here:

  1. Synchronous function calls: where the main thread executes the whole function block and never returns control until it's all finished executing. You don't need a callback for this sort of thing, you just call your function in-line.

// some code func() // some more code `

  1. Asynchronous functions, which need some time to execute. In order not to block the main thread (usually the UI thread itself), the code is deferred till some time later when the engine can spare some processing cycles. This is where you need callbacks. It looks like this:

// some code async_func(callback_func) // some more code

There is no guarantee that all the code inside async_func will execute before some more code is. In fact, it will most probably execute later.

From the names of your functions, it doesn't look like any of them is doing any actual async work. So you can just call them like so:

function doEverything() {
    parseText()
    scrollToTop()
    removeOldElements()
}

In addition, you forgot the parentheses for the last function call removeoldElements(), that's why it didn't execute.

yelsayed
  • 5,236
  • 3
  • 27
  • 38
  • OP mentioned that `scrollToTop` function "causes the window to load more DOM elements".. maybe that's where it is async? – Soubhik Mondal May 05 '16 at 02:02
  • The parentheses were not the reason the code didn't execute. He was specifying the return value of parseText to be the callback. In JavaScript it's quite common to reference functions as arguments because it prevents you from having to write `scrollToTop(function(){removeOldElements();});`. – Martijn May 05 '16 at 02:03
  • 1
    The only thing that is "async" I suppose (if I understand the definition of the term properly) is that when I call scrollToTop() it causes the DOM to load more elements, so I have to wait until those are loaded before running removeOldElements(), which.. I'm not sure is this is what callbacks are for, actually. – shan May 05 '16 at 02:06
  • @Martijn that's assuming `scrollToTop()` really is an async function, which isn't obvious from the code above. If so then you're right, but it could be the OP's own implementation. – yelsayed May 05 '16 at 02:06
  • @shanling it would help if you can provide the implementation for your functions, we can't tell which is async and which is not. Yes, if `scrollToTop()` is an async function, you'll need to pass a callback that handles the rest of your logic. – yelsayed May 05 '16 at 02:08
  • @Yasser correct, but I was referring to a sort of "normal" scenario in which developers specify a callback argument and how that should be used. – Martijn May 05 '16 at 02:09
  • Gah, I think maybe I asked the wrong question then. Should I edit my original or just post a new one..? – shan May 05 '16 at 02:10
  • @shanling a good rule of thumb is if you can specify a callback, it is almost always asynchronous. If you can't it's more likely synchronous than asynchronous. – Martijn May 05 '16 at 02:11
  • @shanling if it's still about using callbacks and asynchronous clals you can just edit the answer. If we're answering a completely different question you can add a new one. Please search SO first, you're likely to find answers to questions like this. – yelsayed May 05 '16 at 02:13
0

Callback is good choice, this example may guide you further.

function one(fn) {
  console.debug('one...');
  setTimeout(fn, 1000);
}

function two(fn) {
  console.debug('two...');
  setTimeout(fn, 1000);
}

function three(fn) {
  console.debug('three...');
  setTimeout(fn, 1000);
}

function loop() {
  console.debug('loop...');
  setTimeout(function() {
    one(function() {
      two(function() {
        three(loop);
      });
    });
  }, 1000);
}

setTimeout(loop, 1000);
Open browser console, for logs.
-3

I'm not sure what you are trying to do, but I suggest to you doing this:

function parseText(callback) {
        //some code here
        console.log("parsetext");
        scrollToTop('callback');
}

function scrollToTop(callback) {
        //some code here
        console.log("scrollToTop");
        removeOldElements();
}

function removeOldElements() {
        //some code here
        console.log("removeOldElements");
        setTimeout(parseText, 5000);
}

ingparseText();