Question

Why my javascript function detected as not function on callback?

recently I try to jump into coding again after stopping for almost 7 years long. What I'm troubled now is a simple case where function became "not" function on callback.

Here is where it happens:

function xhrcall() {
   let xhr = new XMLHttpRequest();
   xhr.responseType = "json";
   xhr.open("POST", "/api", true);
   xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
   xhr.send("token=xxxxxxx");
   xhr.onload = () => {
      let x = xhr.status == 200 ? xhr.response : false;     //console.log(x) gives proper response
      return x;
   }
}

When I try to declare it in variable or use it as callback it gives me Uncaught Error.

For example if I declare it like this

let fn = xhrcall()
console.log(fn)        //will gives me undefined result
window.callback = xhrcall()
callback()             //will gives uncaught error not a function

As I recalled, this should be fine and working yet it not.

This could be duplicate questions but I hope someone could explain what is actually wrong here. Did I miss the function scope? or is it the problem with return x?

Thank you.

 2  56  2
1 Jan 1970

Solution

 3

By default, if a function's execution doesn't end at a return statement, or if the return keyword doesn't have an expression after it, then the return value is undefined.

xhrcall() returns undefined [1]

This value is assigned to fn and neither the global property undefined nor the primitive value undefined are invocable hence your observations are consistent.


If you need the value that the arrow function assigned to xhr.onload will return, you have to find a different way to collect that value since the arrow function will not be invoked synchronously.

You can collect that value using an EventTarget that an Event will be dispatched to when the arrow function assigned to xhr.onload is fired and completes. Event listeners listening to this EventTarget will be invoked when this Event is dispatched.

For example:

const xhrApiTarget = new EventTarget()
xhr.onload = () => {
    let x = xhr.status == 200 ? xhr.response : false
    const apiResEvt = new Event("api-res")
    apiResEvt.response = x
    xhrApiTarget.dispatchEvent(apiResEvt)
}
xhrApiTarget.addEventListener("api-res", (apiResEvt) => { apiResEvt.response })

[1] Don’t confuse with the return in the arrow function assigned to xhr.onload.

2024-07-20
Chukwujiobi Canon