How to resolve promise in render - async-await

In my code, I need to call a function that gives the API response data. am getting the result in promise. how to resolve it in the render method. The function this.metaDataFetch(); called in render.
class Layout extends Component {
metaDataFetch = async function (context) {
let metaContentData = await getMetaContent(parameter);
let metacontent = {};
let data = metaContentData.data;
if(data && data.length){
await data.map((element) => {
let elements = element.attribute;
metacontent[elements] = element.values || null
})
}
return metacontent;
}
render() {
let data = this.metaDataFetch();
console.log("data is <pending>" , data)
return (
<>
<Header pageProps={pageProps} match={this.props.match}/>
<Footer/>
</>
);
}
}
export default Layout;

Related

NextJS API Route Returns Before Data Received?

I'm not sure what's going on here. I have set up an API route in NextJS that returns before the data has been loaded. Can anyone point out any error here please?
I have this function that calls the data from makeRequest():
export async function getVendors() {
const vendors = await makeRequest(`Vendor.json`);
console.log({ vendors });
return vendors;
}
Then the route: /api/vendors.js
export default async (req, res) => {
const response = await getVendors();
return res.json(response);
};
And this is the makeRequest function:
const makeRequest = async (url) => {
// Get Auth Header
const axiosConfig = await getHeader();
// Intercept Rate Limited API Errors & Retry
api.interceptors.response.use(
function (response) {
return response;
},
async function (error) {
await new Promise(function (res) {
setTimeout(function () {
res();
}, 2000);
});
const originalRequest = error.config;
if (error.response.status === 401 && !originalRequest._retry) {
token[n] = null;
originalRequest._retry = true;
const refreshedHeader = await getHeader();
api.defaults.headers = refreshedHeader;
originalRequest.headers = refreshedHeader;
return Promise.resolve(api(originalRequest));
}
return Promise.reject(error);
}
);
// Call paginated API and return number of requests needed.
const getQueryCount = await api.get(url, axiosConfig).catch((error) => {
throw error;
});
const totalItems = parseInt(getQueryCount.data['#attributes'].count);
const queriesNeeded = Math.ceil(totalItems / 100);
// Loop through paginated API and push data to dataToReturn
const dataToReturn = [];
for (let i = 0; i < queriesNeeded; i++) {
setTimeout(async () => {
try {
const res = await api.get(`${url}?offset=${i * 100}`, axiosConfig);
console.log(`adding items ${i * 100} through ${(i + 1) * 100}`);
const { data } = res;
const arrayName = Object.keys(data)[1];
const selectedData = await data[arrayName];
selectedData.map((item) => {
dataToReturn.push(item);
});
if (i + 1 === queriesNeeded) {
console.log(dataToReturn);
return dataToReturn;
}
} catch (error) {
console.error(error);
}
}, 3000 * i);
}
};
The issue that I'm having is that getVendors() is returned before makeRequest() has finished getting the data.
Looks like your issue stems from your use of setTimeout. You're trying to return the data from inside the setTimeout call, and this won't work for a few reasons. So in this answer, I'll go over why I think it's not working as well as a potential solution for you.
setTimeout and the event loop
Take a look at this code snippet, what do you think will happen?
console.log('start')
setTimeout(() => console.log('timeout'), 1000)
console.log('end')
When you use setTimeout, the inner code is pulled out of the current event loop to run later. That's why end is logged before the timeout.
So when you use setTimeout to return the data, the function has already ended before the code inside the timeout even starts.
If you're new to the event loop, here's a really great talk: https://youtu.be/cCOL7MC4Pl0
returning inside setTimeout
However, there's another fundamental problem here. And it's that data returned inside of the setTimeout is the return value of the setTimeout function, not your parent function. Try running this, what do you think will happen?
const foo = () => {
setTimeout(() => {
return 'foo timeout'
}, 1000)
}
const bar = () => {
setTimeout(() => {
return 'bar timeout'
}, 1000)
return 'bar'
}
console.log(foo())
console.log(bar())
This is a result of a) the event loop mentioned above, and b) inside of the setTimeout, you're creating a new function with a new scope.
The solution
If you really need the setTimeout at the end, use a Promise. With a Promise, you can use the resolve parameter to resolve the outer promise from within the setTimeout.
const foo = () => {
return new Promise((resolve) => {
setTimeout(() => resolve('foo'), 1000)
})
}
const wrapper = async () => {
const returnedValue = await foo()
console.log(returnedValue)
}
wrapper()
Quick note
Since you're calling the setTimeout inside of an async function, you will likely want to move the setTimeout into it's own function. Otherwise, you are returning a nested promise.
// don't do this
const foo = async () => {
return new Promise((resolve) => resolve(true))
}
// because then the result is a promise
const result = await foo()
const trueResult = await result()

Rx Js - create an observer for $.ajax Complete()

I have an ajax call for an insert operation. I need to update a grid (future there might be many) once the ajax call completed. How to do this using Rx Js.
I have done something with event based but it won't work out for my case.
NOTE: save ajax call is in different script file.
var submitButton = document.querySelector('.btn-primary');
var refresh1ClickStream = Rx.Observable.fromEvent(submitButton, 'click');
var requestStream = refresh1ClickStream.startWith('startup click')
.map(function () {
var max = 10;
return 'http://localhost/.../GetPayments';
});
var responseStream = requestStream
.flatMap(function (requestUrl) {
return Rx.Observable.fromPromise($.getJSON(requestUrl));
});
function createSuggestionStream(closeClickStream) {
return closeClickStream.startWith('startup click')
.combineLatest(responseStream,
function (click, data) {
return data;
}
)
.merge(
refresh1ClickStream.map(function () {
return null;
})
)
.startWith(null);
}
var paymentStream = createSuggestionStream(refresh1ClickStream);
//var pfaStream = createSuggestionStream(refresh1ClickStream);
// Rendering ---------------------------------------------------
function renderSuggestion(payments, selector) {
//render grid
}
paymentStream.subscribe(function (payment) {
renderSuggestion(payment, 'payment1');
});
//pfaStream.subscribe(function (pfa) {
// renderSuggestion(pfa, 'tblPayFromAccount');
//});

fetch returning promise rather than value

Hopefully the code below communicates the problem clearly. The issue is that in the module which uses the get method of fetchData, the value being returned is the actual Promise, rather than the JSON as desired. Any thoughts on this?
// fetchData.js module
var _ = require('lodash');
function get() {
var endpoint1 = `/endpoint1`;
var endpoint2 = `/endpoint2`;
return fetch(endpoint1)
.then((endpoint1Response) => {
return endpoint1Response.json()
.then((endpoint1JSON) => {
return fetch(endpoint2)
.then((endpoint2Response) => {
return endpoint2Response.json()
.then((endpoint2JSON) => {
var data = _.merge({}, {json1: endpoint1JSON}, {json2: endpoint2JSON});
console.log('data in fetch', data); // this logs the json
return data;
});
});
});
});
}
exports.get = get;
// module which uses get method of fetchData get
var fetchData = require('fetchData');
var data = fetchData.get();
console.log('returned from fetchData', data); // this logs a Promise
Yes, that's exactly what's supposed to happen. The whole point of promises is that their result value is not immediately available and that doesn't change just because you're obtaining one from a separate module.
You can access the value like this:
var fetchData = require('fetchData');
fetchData.get().then(data =>
console.log('returned from fetchData', data);
);
Also note that you are using promises in a non-idiomatic way and creating a "tower of doom." This is much easier on the eyes and accomplishes the same thing:
function fetchJson(endpoint) {
return fetch(endpoint)
.then(endpointResponse => endpointResponse.json());
}
function get() {
var endpoint1 = `/endpoint1`;
var endpoint2 = `/endpoint2`;
return Promise.all([fetchJson(endpoint1), fetchJson(endpoint2)])
.then(responses => {
var data = { json1: responses[0], json2: responses[1] };
console.log('data in fetch', data); // this logs the json
return data;
});
}
Edit I haven't used async/await in JavaScript, but to answer your question, I presume this would work:
async function fetchJson(endpoint) {
var res = await fetch(endpoint);
return res.json();
}
async function get() {
var endpoint1 = `/endpoint1`;
var endpoint2 = `/endpoint2`;
var data = {
json1: await fetchJson(endpoint1),
json2: await fetchJson(endpoint2)
};
console.log('data in fetch', data); // this logs the json
return data;
}
// module which uses get method of fetchData get
async function main() {
var fetchData = require('fetchData');
var data = await fetchData.get();
console.log('returned from fetchData', data);
}
return main();

updating variable after ajax call made in angularjs

I use factory to make database calls in angularjs
var app = angular.module('myApp', []);
app.factory("Service", function ($http) {
var obj = {};
$http.get('test.txt').then(function (data) {
obj.getApiKey = {'Authorization' : data.data};
});
return obj;
});
app.factory("Orders", function ($http, Service) {
var obj = {};
var api_key = Service.getApiKey;
console.log(api_key);
return obj;
});
In the above program, when i call property of Service factory and log the value of api_key = Service.getApiKey; it shows undefined. Probably its because the data is not received from $http call. How to perform the AJAX call synchronously.
var app = angular.module('myApp', []);
app.factory("Service", function ($http) {
var obj = {};
factory.get=function(success,error){
$http.get('test.txt').then(function (data) {
obj.getApiKey = {'Authorization' : data.data};
});
return obj;
}
});
app.factory("Orders", function ($http, Service) {
Service.get(suc,err);
var suc=function()
{
var obj = {};
var api_key = Service.getApiKey;
console.log(api_key);
return obj;
}
});
As noted by Jonathan, it's not best practice you not use synchronous calls with AJAX, instead, you can return a promisse as a funcion and use it later:
var app = angular.module('myApp', []);
app.factory("Service", function ($http) {
var obj = {};
obj.getApiKey = $http.get('test.txt').then(function (data) {
return {'Authorization' : data.data};
});
return obj;
});
app.factory("Orders", function ($http, Service) {
var obj = {};
obj.getApiKey = Service.getApiKey.then(function(data){
console.log(data);
return data;
});
return obj;
});
In this case, the service is returning a promisse object, this way you can ensure values will be called successfully and data will be available after the call.
Return a Promise from your service:
app.factory("Service", function ($http) {
return {
getApiKey: function() {
return $http.get('test.txt');
}
};
});
Inject your service, and use the Promise API to get your data asynchronously:
app.factory("Orders", function ($http, Service) {
var obj = {};
var api_key = {};
Service.getApiKey().then(function(apiKey) {
api_key = apiKey.data;
});
});

How to make an ajax call asynchronous?

I was trying to retrieve CRM records using Ajax calls.
function RetrieveCrmRecords(entName, fields, filter, callback, orderby, errcallback) {
///<summary>
/// function to Retrieve Multiple CRM records.
///</summary>
//debugger;
var async = !!callback;
var setEntityName = entName + 'Set';
var _callback = callback;
filter = (filter) ? "&$filter=" + filter : '';
var query1 = CrmServerUrl + ODATA + "/";
var query2 = setEntityName + "()" + "?";
var queryUrl = query1 + query2;
if (fields != null) queryUrl += "$select=" + fields.join(',');
if (orderby != null) {
if (fields != null) {
queryUrl += '&';
}
queryUrl += "$orderby=" + orderby;
}
queryUrl += filter;
var performRequest = function (queryUrl, fnCallback) {
var async = !!fnCallback;
var opts = { url: queryUrl }
return _makeRequest(opts, async, function (data) {
var nextData = data.__next || null;
var resultsData = data.results || data;
var responseData = { 'results': resultsData, 'next': nextData }
if (nextData) {
responseData.LoadNext = function (callback) {
return performRequest(nextData, callback);
};
}
if (async) {
fnCallback(responseData);
}
else {
return responseData;
}
}, errcallback);
};
return performRequest(queryUrl, callback);
}
As I don't have that much idea about ajax calls, its hard to make this function Asynchronous for me.
Experts please help me to understand that this function is synchronous because of var async = !!callback; this?
If in place of this line I write var async=true; can it make this function asynchronous?
Thanks in advance.
I think i got you exactly what you are asking for.
Please don't get look into this file from where you have copied and pasted this function.
This will make you confuse if you are new for this.
Just call the function from your .js File like this.
function RetrieveCrmRecords(entName, fields, filter, calledForAsync, orderby, errcallback) {
//Your Code
}
function calledForAsync()
{
//Your Code
}
When Operation in RetrieveCrmRecords() will completed rest code will execute finely and then it will come into the calledForAsync().
This is called Async Call.
I hope you were asking for this.
Thanks,
Anish.

Resources