gw1500se Posted August 15, 2022 Share Posted August 15, 2022 I have a function that uses fetch which is an asynchronous function. After reading on how to wait for the result I am unable to figure out how to do the wait. Here is my script: function requests(url) { fetch(url) .then(response => { // indicates whether the response is successful (status code 200-299) or not if (!response.ok) { throw new Error(`Request failed with status ${response.status}`) } return response.json() }) .then(data => { console.log(data.num_results) return(data.results) }) .catch(error => console.log("Auto_select: "+error)) } var json_formatted_str, obj; console.log("Getting page data"); json_formatted_str = requests("https://worker.mturk.com/projects.json"); console.log(json_formatted_str); Can someone help me set this function up so it does not return until the fetch completes? TIA. Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/ Share on other sites More sharing options...
Barand Posted August 15, 2022 Share Posted August 15, 2022 Google turned up this https://rapidapi.com/guides/fetch-api-async-await Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599400 Share on other sites More sharing options...
gw1500se Posted August 15, 2022 Author Share Posted August 15, 2022 Thanks. I saw that but I can't figure out how to do that in the context of my function and how to return the value: async function requests(url) { const x=await fetch(url) .then(response => { // indicates whether the response is successful (status code 200-299) or not if (!response.ok) { throw new Error(`Request failed with status ${response.status}`) } await return response.json() }) .then(data => { console.log(data.num_results) return(data.results) }) .catch(error => console.log("Auto_select: "+error)) } var json_formatted_str, obj; console.log("Getting page data"); json_formatted_str = requests("https://worker.mturk.com/projects.json"); console.log(json_formatted_str); Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599401 Share on other sites More sharing options...
requinix Posted August 15, 2022 Share Posted August 15, 2022 At the top-level you do not use awaits, and instead the Javascript runtime will handle them. As in, if it finds a dangling Promise somewhere then it will go ahead and let it run to completion. That's why you can call fetch().then().catch() without having to await anything yourself. You also do not need to use await inside the .then(). It's okay to return a Promise, which is what .json() will return. That Promise it returns then gets "unwrapped" before the next .then kicks in. In other words, why are you adding async/await in the first place? Is there a reason, or are you just trying to learn more about it? Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599402 Share on other sites More sharing options...
Barand Posted August 15, 2022 Share Posted August 15, 2022 I feel your pain. Fetch syntax is far too cryptic for me. Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599403 Share on other sites More sharing options...
kicken Posted August 15, 2022 Share Posted August 15, 2022 Usually you'll want to use async/await or then/catch, not both. You can do both, but it makes the code a bit more confusing. await can only be used in async functions, not in the global scope. In the global scope you're stuck using then/catch. async function requests(url) { const response = await fetch(url); if (!response.ok){ throw new Error(`Request failed with status ${response.status}`) } const data = await response.json(); console.log(data.num_results) return data.results; } console.log("Getting page data"); //If this were in another async function, you could await. If it's top level, you have to then. requests("https://worker.mturk.com/projects.json").then(results => { console.log(results); }).catch(error => console.log("Auto_select: "+error)); Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599404 Share on other sites More sharing options...
gw1500se Posted August 15, 2022 Author Share Posted August 15, 2022 (edited) 9 minutes ago, requinix said: In other words, why are you adding async/await in the first place? Is there a reason, or are you just trying to learn more about it? That's a confusing statement. My understanding is that the fetch returns immediately since it is an async process. This whole thing is confusing and a tough nut for me to crack. Edited August 15, 2022 by gw1500se Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599405 Share on other sites More sharing options...
Strider64 Posted August 15, 2022 Share Posted August 15, 2022 /* Handle General Errors in Fetch */ const handleErrors = function (response) { if (!response.ok) { throw (response.status + ' : ' + response.statusText); } return response.json(); }; /* Success function utilizing FETCH */ const UISuccess = (data) => { console.log(data); // Parsed Data coming back from Ajax }; const UIError = (error) => { console.log("Database Table did not load", error); }; /* create FETCH request */ const createRequest = (url, succeed, fail) => { fetch(url) .then((response) => handleErrors(response)) .then((data) => succeed(data)) .catch((error) => fail(error)); }; /* Call the createRequest function const NameOfFunction () => {} */ createRequest(requestUrl, UISuccess, UIError); I found breaking down FETCH in separate function calls to be easier to understand. Maybe this will help? Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599406 Share on other sites More sharing options...
requinix Posted August 16, 2022 Share Posted August 16, 2022 4 hours ago, gw1500se said: That's a confusing statement. My understanding is that the fetch returns immediately since it is an async process. This whole thing is confusing and a tough nut for me to crack. fetch returns a Promise immediately. That does not mean the Promise has been resolved yet. Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599409 Share on other sites More sharing options...
gw1500se Posted August 16, 2022 Author Share Posted August 16, 2022 (edited) 12 hours ago, kicken said: Usually you'll want to use async/await or then/catch, not both. You can do both, but it makes the code a bit more confusing. await can only be used in async functions, not in the global scope. In the global scope you're stuck using then/catch. I tried using your code and it seems to work. However, what I am getting is not quite what I need. It appears that 'results' shows 2 arrays. I want to put the 2nd array into a variable for processing. When I do something like 'hits=results[1]' I don't really get the same thing in the array that is logged. This is the result of the 'console.log(results)' (unexpanded): >Array(0) >Array(53) How do I put the 2nd array into a variable I can process as an array? I tried 'hits=results[1]' but I get the first element of the 2nd array. Edited August 16, 2022 by gw1500se Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599426 Share on other sites More sharing options...
gw1500se Posted August 16, 2022 Author Share Posted August 16, 2022 Time to do a reset. This may need to be a new thread. Here is my current code: async function requests(url) { const response = await fetch(url); if (!response.ok) { throw new Error(`Request failed with status ${response.status}`) } const data = await response.json(); return data.results; } console.log("Getting page data"); hits=requests("https://worker.mturk.com/projects.json").then(results => { return(results); }).catch(error => console.log("auto_select: "+error)); console.log(hits); The console log now shows this (unexpanded): \/Promise >[[Prototype]]: Promise >[[PromiseState]]: "fulfilled" >[[PromiseResult]]: Array(55) This doesn't seem like normal json but I need to get that array into a variable. Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599438 Share on other sites More sharing options...
kicken Posted August 16, 2022 Share Posted August 16, 2022 Anything you want to do with the results of a promise must be done either after using await or within the .then method. Just ignore the return value from your requests function and do whatever work you want to do within the .then method. Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599446 Share on other sites More sharing options...
gw1500se Posted August 16, 2022 Author Share Posted August 16, 2022 All I want to do is get that array outside of the function. The processing I need to to on it is going to be too much. Plus the function would then have to be recursive as the data within the array will require additional fetches. Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599452 Share on other sites More sharing options...
kicken Posted August 16, 2022 Share Posted August 16, 2022 Think of promises like events, they work similarly in that there's an unknown delay you have to account for. What you seem to be trying to do so far would be the equivalent of var whichKey; input.addEventListener('keypress', (e) => { whichKey = e.keyCode; }); console.log('You typed: ' + whichKey); The code isn't going to wait around for the key press before moving onto the console.log statement. It'll just move on, log that you typed nothing and then run the key press code later whenever you actually press a key. It's the same with your fetch statement here. The code isn't going to just hang around waiting for the fetch to complete before moving on. As such, any code which depends on the results of the fetch must be integrated into the .then callback function. await lets you code as if everything just stopped and waited, but must be combined with async and cannot be used at the global scope. Without knowing more about the rest of your code, it's hard to say what your solution needs to be. If this fetch request is being made from some event handler, then all you'd likely need to do is make your event handler function async and then await the result. window.addEventListener('DOMContentLoaded', async (e) => { const data = await requests('/'); console.log(data); }); If that's not possible for some reason, you might need to do more restructuring of the code. Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599453 Share on other sites More sharing options...
gw1500se Posted August 16, 2022 Author Share Posted August 16, 2022 (edited) I think we are missing my question which is why I thought a new thread is needed. I have the data outside of the function but I don't recognize the format it is in so I don't know how to extract that array I need. The variable (hits) is typeof 'obj'. Edited August 16, 2022 by gw1500se Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599458 Share on other sites More sharing options...
kicken Posted August 16, 2022 Share Posted August 16, 2022 9 minutes ago, gw1500se said: I have the data outside of the function No, you don't according to what you've posted so far. Your hits variable is just the promise object that you get as a result of calling fetch(). The data you want is provided to the callback you pass into the .then function of that promise. Your code return(results) in the .then function does not return that value into hits, it pass that value into the next .then function if there was one. Without one it just does nothing. If you're still stuck, or think I'm still not understanding the problem I think you'll need to provide more code/context. Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599459 Share on other sites More sharing options...
gw1500se Posted August 16, 2022 Author Share Posted August 16, 2022 There isn't any more code (I guess that is the problem). Are you saying I need another .then to return the results of the fetch? Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599460 Share on other sites More sharing options...
kicken Posted August 16, 2022 Share Posted August 16, 2022 4 minutes ago, gw1500se said: Are you saying I need another .then to return the results of the fetch? No, you just need to do whatever you want to do with the results inside the .then function rather than try and return the data back outside of the function somehow. Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599462 Share on other sites More sharing options...
gw1500se Posted August 16, 2022 Author Share Posted August 16, 2022 (edited) OK, although that seems impractical given what I need to do with the array contents. I think the function then becomes superfluous if I can't get anything outside of it. We no longer have a .then. I don't know where that would go given the current code. Edited August 16, 2022 by gw1500se Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599463 Share on other sites More sharing options...
kicken Posted August 16, 2022 Share Posted August 16, 2022 I don't know what you need to do with the results, that's why I suggested posting more code. It might be that the way the await/async syntax works that is tripping you up. await is only usable within a function marked as async. Any function that is marked as asyc automatically returns a Promise object. Even if it looks like you're returning some specific value, you're not. Whatever value you return from the function ends up being the result of the promise which is given to any attached .then handlers (or as the result of await). So this code: async function requests(url) { const response = await fetch(url); if (!response.ok) { throw new Error(`Request failed with status ${response.status}`) } const data = await response.json(); return data.results; } Does not return your result data like you might expect by looking at it. That code is just a "modern" / "cleaned up" version of the more traditional: function requests(url) { return fetch(url).then(function(response){ if (!response.ok) { throw new Error(`Request failed with status ${response.status}`) } return response.json(); }).then(function(data){ return data.results; }); } That should be easier to see that what the requests() function returns is a Promise, not data.results. So you'd then take that returned promise and add your .then() handler to process whatever the results are. requests('/').then(function(results){ for (let item of results){ console.log(item); } }); Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599464 Share on other sites More sharing options...
gw1500se Posted August 16, 2022 Author Share Posted August 16, 2022 (edited) First this is a Chrome extension. I haven't developed any more code yet since I am not sure what elements will be returned. The results of that fetch produces a large array of json elements. Depending on filters I have to build to analyze each array element, I need to issue another fetch for specific elements. After processing that, if it meets certain criteria, I will pass that information to another extension's API. The process will need to continue to be repeated every 'n' time periods. Perhaps I need an alternative method for getting my data but fetch seems like the only way to get data from a URL in javascript. Edited August 16, 2022 by gw1500se Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599465 Share on other sites More sharing options...
kicken Posted August 16, 2022 Share Posted August 16, 2022 Wrap your code in a single async function and call it. Then you can code in a more traditional style using await. When it comes time to do the "repeat every N time periods" part you can then pass that function to a call to setInterval. Example: function requests(url) { return fetch(url).then(function(response){ if (!response.ok) { throw new Error(`Request failed with status ${response.status}`) } return response.json(); }); } async function myExtension(){ const data = await requests('https://worker.mturk.com/projects.json'); for (let item of data.results[1]) { console.log(item); } } myExtension(); // When you're ready to repeat: //setInterval(myExtension, 5000); 1 Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599467 Share on other sites More sharing options...
gw1500se Posted August 16, 2022 Author Share Posted August 16, 2022 Thanks. I don't need the '[1]' but I have what I want now. On to the next layer of the onion. Quote Link to comment https://forums.phpfreaks.com/topic/315187-using-asyncawait/#findComment-1599468 Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.