fetch('https://swapi.dev/api/people/1/') .then(res => res.json()) .then(luke => renderTable(document.body, luke)) function renderTable(parent, obj) { let $table = document.createElement('table') for(let key in obj) { let $tr = document.createElement('tr') let $td = document.createElement('td') let $td2 = document.createElement('td') if(Array.isArray(obj[key])) { for(let item of obj[key]) { let newTable = document.createElement('table') let newTr = document.createElement('tr') let newTd = document.createElement('td') linkChecker(item, newTd) newTr.append(newTd) newTable.append(newTr) $td2.append(newTable) } } else { linkChecker(obj[key], $td2) } $td.innerHTML = key $tr.append($td, $td2) $table.appendChild($tr) } parent.appendChild($table) } function linkChecker(str, container) { if(typeof str === 'string') { if(str.includes('https://swapi.dev/api/')) { let btn = document.createElement('button') btn.innerHTML = 'Show' btn.onclick = () => { fetch(str).then(r => r.json()) .then(r => renderTable(container, r)) // .then(r => console.log(r)) } container.append(btn) } else { container.innerHTML = str } } } function myFetch(url){ return new Promise(function (resolve, reject){ const xhr = new XMLHttpRequest() xhr.open('get', url) xhr.onload = function () { if (xhr.status >= 200 && xhr.status < 300) { resolve(xhr.response); } else { reject(() => alert('something went wrong')); } xhr.send(); }}); } myFetch('https://swapi.dev/api/peope/4/') .then(res => console.log(res)) function delay(ms) { return setTimeout(() => console.log('delay worked'), ms) } Promise.race([myFetch('https://swapi.dev/api/peope/4/'), delay(300)]).then(val => console.log(val)) Promise.race([myFetch('https://swapi.dev/api/peope/1/'), delay(200)]).then(val => console.log(val))