0

In an HTML document, a script is run when the page loaded and the JS defines a series of chained together functions, all called whenever the previous one is done. I have a number of questions with this example:

  1. Why is f1 undefined?
  2. Am I supposed to be able to define functions f1, ..., f4 also within callbacksInit, so as not to pollute the global namespace?
  3. Am I supposed to be able to define functions f1, ..., f4 in the JS document after callbacksInit?

var f1 = function() { console.log("Running f1"); }
var f2 = function() { console.log("Running f2"); }
var f3 = function() { console.log("Running f3"); }
var f4 = function() { console.log("Running f4"); }


function callbacksInit() {
    function start() {
        f1()
        .done(f2)
        .done(f3)
        .done(f4);
    }
    start();
}
<!DOCTYPE html>
<html>
    <head>
        <script type="text/javascript" src="./callbacks.js"></script>
    </head>

    <body onload="callbacksInit()">
        <main>
            <h1>CALLBACKS ASYNC</h1>
        </main> 
    </body> 
</html>

6
  • 3
    f1() returns undefined and you expect it to be a Promise Commented Apr 23, 2020 at 13:13
  • 1
    your functions dont return anything. But you calling done on the result Commented Apr 23, 2020 at 13:14
  • what do I need to return then? Commented Apr 23, 2020 at 13:15
  • 1
    You need to return a Promise. Or make those async function, in which case they will implicitly return a Promise. However, since you don't have any async functionality, I don't know why you want to chain .done here. Commented Apr 23, 2020 at 13:16
  • 1
    Then either return the promise from that DB call (it's most likely a Promise, otherwise you can convert it yourself) or use async/await for those functions which is basically equivalent but you may prefer to just use await everywhere. Commented Apr 23, 2020 at 13:29

3 Answers 3

1

a function by itself does not return anything, hence the undefined

const a = () => { 
  console.log("Running f1"); 
}

// returns "undefined"
const b = () => { 
  console.log("Running f1"); 
  return 'b';
}

// returns "b"

BTW there is no such thing as done() apart of jQuery deferred mode, but to use that, you need to use jQuery, that's not in the tag

you need to return a Promise object, like

function a() {
  return new Promise( function(resolve, reject) {
    // now you can either:
    // return resolve('data')
    // return reject(new Error('My error message'))
  });
}

by returning a promise you can now use the normal callback hell 🤦‍♂️

function callbacksInit() {
    function start() {
        f1()
        .then(function(data1) { f2() })
        .then(function(data2) { f3() })
        .then(function(data3) { f4() })
        .then(function(data4) { /* done, continue here */ })
        .catch(function(err) {
           console.log(err.message) // the message of the error upon reject()
        });
    }
    start();
}

or use async/await

function callbacksInit() {
    function async start() {
        try { // there's no "catch" in async/await so we wrap all in try/catch
           var data1 = await f1()
           var data2 = await f2()
           var data3 = await f3()
           var data4 = await f4()
       } catch(err) {
           console.log(err.message) // the message of the error upon reject()
       }
    }
    start();
}

Important NOTE

Always return an Error object when rejecting a Promise, will make things so much easier for you in the future 😁

Sign up to request clarification or add additional context in comments.

Comments

0

You are calling f1() which basically returns void, it doesn't return anything and then you are trying to access a function done() it it, but since the return value is undefined then it had nothing.

we are not talking about async functions here or anything, what's wrong with just calling them one after another?

f1()
f2()
f3()
f4()

This should do the trick, they are not async so each one will just run after the previous one has finished.

Am I missing something here?

1 Comment

Thanks, sure that would be ok, but in my context I have to go async because the fs are calling a DB
0

The function f1 is defined, however the .done called on it is not. In order for you to actually execute the functions one after the other(considering each function has some async actions within it), you need to return Promise from them which resolves once the function is executed.

Also use .then instead of .done

var f1 = function() { console.log("Running f1"); return Promise.resolve()}
var f2 = function() { console.log("Running f2"); return Promise.resolve()}
var f3 = function() { console.log("Running f3"); return Promise.resolve()}
var f4 = function() { console.log("Running f4"); return Promise.resolve()}


function callbacksInit() {
    function start() {
        f1()
        .then(f2)
        .then(f3)
        .then(f4);
    }
    start();
}
<!DOCTYPE html>
<html>
    <head>
        <script type="text/javascript" src="./callbacks.js"></script>
    </head>

    <body onload="callbacksInit()">
        <main>
            <h1>CALLBACKS ASYNC</h1>
        </main> 
    </body> 
</html>

For a normal synchronous function, you can directly call them like

function callbacksInit() {
    function start() {
        f1();
        f2();
        f3();
        f4();
    }
    start();
}

and they will all execute one after the other

2 Comments

Do i need jQuery for Promise.resolve()? And why then instead of done?
No, Promise is a native javascript API

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.