1

My function has to call two endpoints and concat them in one string at the same time. My code is simply a function that is getting two endpoints at the same time and print it in console. But the same function has to concat them to one string. I tried to create separated variables contains each call and then simply concat them, but the result hadn't been any different. I read about it for couple of hours, and I see no, even the smallest tip anywhere. EDIT: Please mind that each endpoint is an actual array.

    function endpointsToOneString() {
        const Http = new XMLHttpRequest();
        const url = 'https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json';
        Http.open("GET", url);
        Http.send();

        Http.onreadystatechange = function () {
            if (this.readyState == 4 && this.status == 200) {
                console.log(Http.responseText)
            }
        }


        const HttpTwo = new XMLHttpRequest();
        const urlTwo = 'https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json';
        HttpTwo.open("GET", urlTwo);
        HttpTwo.send();

        HttpTwo.onreadystatechange = function () {
            if (this.readyState == 4 && this.status == 200) {
                console.log(Http.responseText)
            }
        }
    }

    endpointsToOneString();

6 Answers6

1

I understand you want to concat the result of two parallel requests. In that case you can use a library like axios. From their docs

function getUserAccount() {
  return axios.get('/user/12345');
}

function getUserPermissions() {
  return axios.get('/user/12345/permissions');
}

axios.all([getUserAccount(), getUserPermissions()])
  .then(axios.spread(function (acct, perms) {
    // Both requests are now complete
  }));

So for your example:

function getEndpoint1() {
  return axios.get('https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json');
}

function getEndpoint2() {
  return axios.get('https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json');
}

axios.all([getEndpoint1(), getEndpont2()])
  .then(axios.spread(function (resp1, resp2) {
    // Both requests are now complete
     console.log(resp1 + resp2)
  }));
Jhon Pedroza
  • 698
  • 6
  • 13
1

In this case you should use Promise feature of javascript.

Here you can learn how to promisify your native XHR. Morever, Here you can find about promise chaining. I have just added Promise in your code but it needs to be refactored.

Update: From comment, you want your response texts as a plain string. But we are actually getting a JSON array as response. So, we need to parse it using JSON.parse() function to make it an array object. Then we need to use .join() method to join all element of the array into a string. See the code below:

function endpointsToOneString() {
    var requestOne = new Promise(function(resolve, reject){
        const Http = new XMLHttpRequest();
        const url = 'https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json';
        Http.open("GET", url);
        Http.onload = function () {
        if (this.status >= 200 && this.status < 300) {
            resolve(Http.response);
        } else {
            reject({
            status: this.status,
            statusText: Http.statusText
            });
        }
        };
        Http.onerror = function () {
        reject({
            status: this.status,
            statusText: Http.statusText
        });
        };
        Http.send();
    });

    var requestTwo = new Promise(function(resolve, reject){
        const HttpTwo = new XMLHttpRequest();
        const urlTwo = 'https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json';
        HttpTwo.open("GET", urlTwo);
        HttpTwo.onload = function () {
        if (this.status >= 200 && this.status < 300) {
            resolve(HttpTwo.response);
        } else {
            reject({
            status: this.status,
            statusText: HttpTwo.statusText
            });
        }
        };
        HttpTwo.onerror = function () {
        reject({
            status: this.status,
            statusText: HttpTwo.statusText
        });
        };
        HttpTwo.send();
    });


    Promise.all([
        requestOne,
        requestTwo
    ]).then(function(result){
     var response = JSON.parse(result[0]).join();
      response += JSON.parse(result[1]).join();
      console.log(response);
    });
}
endpointsToOneString();
Adnan Sharif
  • 919
  • 7
  • 17
  • I used promises like this (with a little help from my friend). Those endpoints are an arrays. I need to concat them and join. I returns undefined to me... https://jsfiddle.net/up7fm4ob/ – Iza Adamska Mar 26 '19 at 16:30
  • @IzaAdamska I have edited my answer. Can you please check current version? However, I have formatted my code according to your format. [See this fiddle](https://jsfiddle.net/u672x9da/). It's working! – Adnan Sharif Mar 26 '19 at 16:40
  • I still see two arrays next to each other - isn't there a solution to have an one actual STRING from those two arrays endpoints? Like... basicaly to manipulate arrays we use concat() and join() method... can't we use it somehow? – Iza Adamska Mar 26 '19 at 16:55
  • @IzaAdamska I have updated my answer. Please check it now. – Adnan Sharif Mar 26 '19 at 17:05
  • This is the result I wanted to achieve. I believe I do not understand this code in all of its shape, but - this is my recruitment task for my first job - I learn javascript only for few months. Now I will study this code to make sure I will be able to use it for the future. Thank you a lot for your effort! – Iza Adamska Mar 26 '19 at 17:13
1

try to have a look on the Promise.all method: https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

As in this answer you should wrap your XHR in a Promise and then handle resolving of all function call. In this way you can access endpoint results in order.

Here's a working fiddle:

function makeRequest(method, url) {
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.open(method, url);
    xhr.onload = function() {
      if (this.status >= 200 && this.status < 300) {
        resolve(xhr.response);
      } else {
        reject({
          status: this.status,
          statusText: xhr.statusText
        });
      }
    };
    xhr.onerror = function() {
      reject({
        status: this.status,
        statusText: xhr.statusText
      });
    };
    xhr.send();
  });
}

let url1 = 'https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json';
let url2 = 'https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json'
Promise.all([makeRequest('GET', url1), makeRequest('GET', url2)])
.then(values => {
  debugger;
  console.log(values);
});

https://jsfiddle.net/lbrutti/octys8k2/6/

lbrutti
  • 1,181
  • 13
  • 19
0

Rather than immediately printing them, save them to local variables, then print them at the end:

function endpointsToOneString() {
    let response;          // this line here declares the local variable
    results = 0;           // counts results, successful or not
    const Http = new XMLHttpRequest();
    const url = 'https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json';
    Http.open("GET", url);
    Http.send();

    Http.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            response = Http.responseText;   //save one string
        }
        if (this.readyState == 4) {
            results++;
        }
    }


    const HttpTwo = new XMLHttpRequest();
    const urlTwo = 'https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json';
    HttpTwo.open("GET", urlTwo);
    HttpTwo.send();

    HttpTwo.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            response += HttpTwo.responseText // save the other string
        }
        if (this.readyState == 4) {
            results++;
        }
    }

    while(results < 2) {}  //loops until both requests finish, successful or not
    console.log(response); //print total string
}

endpointsToOneString();

Also, HttpTwo's onreadystatechange function is calling for Http.responseText, rather than HttpTwo.responseText. Fix that as well for best results.

EDIT: Thanks for the tip, Jhon Pedroza!

EDIT: Noah B has pointed out that the above is dirty and inefficient. They are entirely correct. Better version based on their suggestion, credit to them:

function endpointsToOneString() {
    let response1 = '', response2 = ''; // this line declares the local variables
    const Http = new XMLHttpRequest();
    const url = 'https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json';
    Http.open("GET", url);
    Http.send();

    Http.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            response1 = Http.responseText;   //save one string
            checkResults(response1, response2);
        }
    }


    const HttpTwo = new XMLHttpRequest();
    const urlTwo = 'https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json';
    HttpTwo.open("GET", urlTwo);
    HttpTwo.send();

    HttpTwo.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            response2 = HttpTwo.responseText; // save the other string
            checkResults(response1, response2);
        }
    }
}

function checkResults(r1, r2) {
    if (r1 != '' && r2 != '') {
        console.log(r1 + r2);
    }
}

endpointsToOneString();
  • 1
    that won't work if the requests don't finish before the console.log is executed – Jhon Pedroza Mar 26 '19 at 15:31
  • 1
    That's super inefficient. Instead of looping until both responses are done, save each response to a separate variable and call a function that will print the responses if both variables have content. – Noah B Mar 26 '19 at 15:40
  • Check the value of results once, in each callback, don't have a loop! – James Mar 26 '19 at 15:47
0
function endpointsToOneString() {
    var response;
    const Http = new XMLHttpRequest();
    const url = 'https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json';
    Http.open("GET", url);
    Http.send();

    Http.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            response = this.responseText;
            HttpTwo.open("GET", urlTwo);
            HttpTwo.send();
        }
    }


    const HttpTwo = new XMLHttpRequest();
    const urlTwo = 'https://baconipsum.com/api/?type=all-meat&paras=3&start-with-lorem=1&format=json';

    HttpTwo.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
           response += this.responseText; 
           console.log(response);
        }
    }
}

endpointsToOneString();

check this out. there's just minimal editing to your code.

Shaikh Amaan FM
  • 312
  • 4
  • 12
  • What if HttpTwo finishes before Http? – Maclain Anderson Mar 26 '19 at 15:39
  • @MaclainAnderson got you..! still we can avoid "Promise" as someone stated above. check the edited code, that should work perfectly. – Shaikh Amaan FM Mar 26 '19 at 16:01
  • Thing is, these endpoints are actual arrays - please check those url's... I was trying promises, but it returns to me undefined... https://jsfiddle.net/up7fm4ob/ – Iza Adamska Mar 26 '19 at 16:29
  • @IzaAdamska what you're trying to achieve? Do you want these endpoints to be stored in array? – Shaikh Amaan FM Mar 26 '19 at 16:55
  • @IzaAdamska btw, for the fiddle you sent, the error in it is within the ajax requests. The onreadystatechange is not assigned with a correct function. Try the traditional way, e.g: Http.onreadystatechange = function() { if(this.readyState==4 && this.status == 200) { resolve(this.responseText); } } – Shaikh Amaan FM Mar 26 '19 at 17:14
0

Is it obligatory for you to use XMLHttpRequest? If not, u had better use fetch, because it returns Promise and with Promise it would be much simpler.

  • No, it is not, but I am a very begginer, I was searching for solutions in the internet to built this code, this way was the only one to be completely understood for me. I know about fetch method, but I still know not enough to use it wisely. – Iza Adamska Mar 26 '19 at 17:19