I’m implementing Promises for the first time in JS and am getting uncaught in promise exception in console log while running the below code.
function data_present() { return new Promise((resolve, reject) => { fetch(api) .then(response => response.json()) .then(message => { console.log(message) if(message && Object.keys(message).length != 0) { resolve() } else { reject() } }) }) }
I am handling the result of the promise return value in the main function as below and am yet getting the uncaught in promise message:
function main() { data_present().then(() => { load_graph() }).catch(() => { data_present() }) }
The logic behind the data_present() is to wait till we get a non-empty JSON response at the API endpoint and keep polling it if JSON response is empty.
The exception I’m getting is as follows:
Uncaught (in promise) undefined (anonymous) @ index.js:34 Promise.then (async) (anonymous) @ index.js:29 data_present @ index.js:26 (anonymous) @ index.js:56 Promise.catch (async) getParametersData @ index.js:55 onclick @ (index):92
Advertisement
Answer
You might think about having one function to get, parse, and return the JSON from the API (no need to wrap your fetch
in a promise as it already returns one), and use your polling function to check the returned data. If it’s correct call one function, otherwise poll getData
again. If there’s an API error log that instead.
I’ve used async/await
here but the principles are the same.
// Simulates an API // If the random number is a modulo of 5 set data // to an object with a key/value pair, otherwise // it set it to an empty object. If the random number // is a modulo of 9 send an error, otherwise send the data. function mockFetch() { return new Promise((res, rej) => { const rnd = Math.floor(Math.random() * 20); const data = rnd % 5 === 0 ? { name: 'Bob' } : {}; setTimeout(() => { if (rnd % 9 === 0) rej('Connection error'); res(JSON.stringify(data)); }, 2000); }); } // `getData` simply gets a response from the API and parses it. // I had to use JSON.parse here rather that await response.json() // because I'm not using the actual fetch API. async function getData() { const response = await mockFetch(); return JSON.parse(response); } // The `poll` function does all the heavy-lifting // first we initialise `count` async function poll(count = 1) { console.log(`Polling ${count}`); // Try and get some data. If it's not an empty object // log the name (or in your case call loadGraph), // otherwise poll the API again after two seconds. // We wrap everything in a `try/catch`. try { const data = await getData(); if (data && data.name) { console.log(data.name); // loadGraph } else { setTimeout(poll, 2000, ++count); } // If the API sends an error log that instead // and poll again after five seconds } catch (err) { console.log(`${err}. Polling again in 5 seconds.`); setTimeout(poll, 5000, 1); } } poll();
And here’s the version based on Dai’s answer:
function mockFetch() { return new Promise((res, rej) => { const rnd = Math.floor(Math.random() * 20); const data = rnd % 5 === 0 ? { name: 'Bob' } : {}; setTimeout(() => { if (rnd % 9 === 0) rej('Connection error'); res(JSON.stringify(data)); }, 2000); }); } async function getData() { const response = await mockFetch(); return JSON.parse(response); } async function delay(time) { return new Promise(res => setTimeout(res, time)); } async function poll(count = 1) { do { console.log(`Polling ${count}`); try { const data = await getData(); if (data && data.name) return data; await delay(2000); } catch (err) { console.log(`${err}. Polling again in 5 seconds.`); await delay(5000); } ++count; } while (count < 10); console.log(`Reached poll limit - ${count}.`); return false; } async function main() { console.log('First'); console.log(await poll()); console.log('Second'); } main();