1

I am trying to create a function that will call a certain PHP file (mineTime.php) through an XMLHTTPRequest and return its value to this function.

Currently I'm having troubles as it's not working and either it returns nothing or it returns undefined or null and I don't know what to do. I think it might have something to do with the onload event..

mineTime.php

<?php
$miningTime = 3600;

echo json_encode($miningTime);
?>

Minion.js

function GetTime() {
  var miningTime = null;
  var xhr = new XMLHttpRequest();
  xhr.onload = function() {
    miningTime = this.responseText;
  }

  xhr.open("GET", "../php/mineTime.php", true);
  xhr.send();

  return miningTime;
}

window.onload = function () {
    var timeToMine = parseInt(GetTime());
    console.log(timeToMine); // outputs: NaN
    var display = document.querySelector('#time'),
        timer = new CountDownTimer(timeToMine),
        timeObj = CountDownTimer.parse(timeToMine);
        ...*code continues*

Thanks in advance!

2 Answers2

1

This is a common issue that new programmers face, especially when dealing with AJAX calls. Even more experienced programmers can have a difficult time grasping AJAX functionality. It's important to remember what the A in AJAX stands for, Asynchronous. This means that the main program will continue to run while another, side program will work to complete some other task, usually referred to as threads. In this instance, you are trying to return miningTime by getting a value from that Asynchronous call. Because that AJAX call is running on a different thread from the main program, miningTime will always be null.

In order to implement this correctly, you need to implement what is known as a callback function. A callback function is a function that is run when an Asynchronous program finishes doing what it was doing.

This is how it should be structured:

    function GetTime(callback) {
      var xhr = new XMLHttpRequest();
      xhr.onload = callback

      xhr.open("GET", "../php/mineTime.php", true);
      xhr.send();
    }

    function callbackFunction() {
      var timeToMine = parseInt(this.responseText);
      console.log(timeToMine); // outputs: NaN
      var display = document.querySelector('#time'),
      timer = new CountDownTimer(timeToMine),
      timeObj = CountDownTimer.parse(timeToMine);
            ...*code continues*
}

    window.onload = function () {
        var callback = callbackFunction
        GetTime(callback) 
}

Note that in Javascript, there are other possible ways of handling this as well. There are things called Promises as well as async/await. This is, in my opinion, the simplest and most vanilla way to do it.

Update: Since you can't have a function with a time parameter, what you can do instead is pass a reference to the function instead. Referencing a function is sort of like copying a function and pasting it somewhere else, whereas calling a function actually runs it. You can discern the two by the parentheses. If open and close parentheses are added after a function name, it will call the function, if they are omitted, the function will merely be referenced.

Eric Brown
  • 1,312
  • 3
  • 15
  • 30
  • I can't have a function that takes the argument time because I'm trying to prevent people from abusing it in the console. – Napakalaking Halimaw Jun 12 '20 at 17:10
  • Not a problem, I will update my answer. – Eric Brown Jun 12 '20 at 17:11
  • Hey, so I've tested your code, but it still gives a ```undefined``` return after calling the GetTime function. Any idea why? – Napakalaking Halimaw Jun 12 '20 at 22:18
  • Just to confirm, does `this.responseText` in the callback Function return as undefined? Or are you referencing that GetTime will return as undefined? – Eric Brown Jun 12 '20 at 22:39
  • I've tried doing this in console: ``` var test = GetTime(test); console.log(test); // outputs: undefined undefined ``` So I guess both return undefined? – Napakalaking Halimaw Jun 12 '20 at 23:41
  • Ok, I see. This is another mistake that people make when starting out working on Asynchronous functions, and that's treating them like regular functions. Callbacks don't return any values, they act more like they are branching off of the main function to do something else. Because of this, `GetTime` will act as a starting point to another set of commands rather than a function that will return a value. Async is a tough concept to grasp because of this. I would recommend looking into Promises and async/await, like what @Dmitriy has in his answer. They make Async a little easier to process. – Eric Brown Jun 13 '20 at 00:19
0

as mentioned by @EricBrown, another way would be to use Promise (Not supported by IE)

function GetTime() {

    return new Promise( (resolve, reject) => {

        var miningTime = null;
        var xhr = new XMLHttpRequest();
        xhr.onload = function() {
            resolve(this.responseText);
        }

        xhr.open("GET", "../php/mineTime.php", true);
        xhr.send();

    })
}

window.onload = async function () {
    const data = await GetTime();
    var timeToMine = parseInt(data);
    console.log(timeToMine); // outputs: NaN
    var display = document.querySelector('#time'),
        timer = new CountDownTimer(timeToMine),
        timeObj = CountDownTimer.parse(timeToMine);
        ...*code continues*