How can I get rid of the "setInterval" in this code construct? - javascript

I need to wait for the necessary changes in the object to finish the function and return the result to the caller. But I could not think of anything better than using "setInterval". I think I'm doing something wrong.
async checkLockBox ({ state, dispatch, commit }, lockBox) {
if (lockBox.layers === 0) {
commit('lockBox', null);
return lockBox.result;
}
await commit('lockBox', lockBox);
return new Promise((resolve) => {
setInterval(async () => {
if (state.lockBox !== null) {
if (state.lockBox.layers === 0) {
await resolve(state.lockBox.result);
await commit('lockBox', null);
}
}
}, 100);
});
},

Related

async await is not working and console not returning an error

I am trying to make an API call with async await but it's not working and not giving errors
here I am trying to call getRace() which returns a promise so I am using await keyword here:
async function RaceInfo(){
await getRace(raceID)
}
and then I call RaceInfo() and use then to handle the response:
RaceInfo().then(res=>{
if(race.status === "in-progress") {
renderAt('#leaderBoard', raceProgress(res.positions))
}else if(race.status === "finished"){
clearInterval(raceInterval) // to stop the interval from repeating
renderAt('#race', resultsView(res.positions)) // to render the results view
}
and then all of them need to be grouped inside a final promise to be called externally:
function runRace(raceID) {
return new Promise(resolve => {
// TODO - use Javascript's built in setInterval method to get race info every 500ms
async function RaceInfo(){
await getRace(raceID)
}
RaceInfo().then(res=>{
if(race.status === "in-progress") {
renderAt('#leaderBoard', raceProgress(res.positions))
}else if(race.status === "finished"){
clearInterval(raceInterval) // to stop the interval from repeating
renderAt('#race', resultsView(res.positions)) // to render the results view
resolve(res)
}
}).catch((err) => {
console.log(err);
})
const raceInterval=setInterval(RaceInfo, 500);
})
}
console is not returning errors, what could be the issue?
You don't return anything from RaceInfo, and race is undefined in callback passed to RaceInfo().then(...)...
function getRace(raceID) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve({status: "finished"}), 300);
})
}
function runRace(raceID) {
return new Promise(resolve => {
// TODO - use Javascript's built in setInterval method to get race info every 500ms
async function RaceInfo() {
// Added return statement
return await getRace(raceID);
}
RaceInfo().then(race => { // Changed paramter name
if(race.status === "in-progress") {
console.log("race in progress");
// renderAt('#leaderBoard', raceProgress(res.positions))
} else if (race.status === "finished") {
console.log("race in progress");
// clearInterval(raceInterval) // to stop the interval from repeating
// renderAt('#race', resultsView(res.positions)) // to render the results view
// resolve(res)
}
}).catch((err) => {
console.log(err);
})
const raceInterval=setInterval(RaceInfo, 500);
});
}
runRace(7);

React wait for one loop (and setState) to finish before another loop

handleSubmit = () => {
this.setState({ modalState: false })
this.state.codeToClass.forEach((code, classId, map) => {
const cr = _.find(this.state.classRoles, { id: classId })
if (code === cr.classCode) {
console.log('here')
this.setState(state => ({
classRoles: state.classRoles.map((cc) => {
console.log(cc.id)
console.log(classId)
console.log(cc.id === classId)
if (cc.id === classId) {
console.log('here1')
return {
...cc,
role: 'TA',
}
}
console.log('what')
return cc
}),
}), ()=> console.log(this.state.classRoles)) //this is called later
} else {
NotificationManager.error('Failed to register as TA.')
}
})
console.log(this.state.classRoles) //this is called first
this.state.classRoles.forEach((c) => {
if (c.role === '') {
api.deleteClassUser(c.id, this.state.user.id)
} else {
api.postAddClass(c.id, this.state.user.id, c.role)
console.log(c)
}
})
EventEmitter.publish('currentlyEnrolled', this.state.classRoles)
}
I'm trying to run the second forEach after the first forEach has finished,i.e. state has been updated. But it keeps running in this order. Is there a way to fix this?
Promise is your friend.
// You map your operations in to Promises.
const promises = this.state.codeToClass.map((code, classId, map) => {
return new Promise(resolve=>{
const cr = _.find(this.state.classRoles, { id: classId })
if (code === cr.classCode) {
console.log('here')
this.setState(state => ({
classRoles: state.classRoles.map((cc) => {
console.log(cc.id)
console.log(classId)
console.log(cc.id === classId)
if (cc.id === classId) {
console.log('here1')
return {
...cc,
role: 'TA',
}
}
console.log('what')
return cc
}),
}), ()=> resolve()) //this is called later
} else {
NotificationManager.error('Failed to register as TA.')
}
})
})
// and then you wait for all of the promises
await Promise.All(promises);
// then continue to execution
There are two options.
Use Promise
Async await
Since map can be used with await, I think
const tempState = this.state.codeToclass;
await tempState.map(...
This way can work :)
this.setState is an asynchronous operation.
You can try something like this:
handleSubmit = () => {
//some code...
this.setState(state => ({
state.codeToClass.forEach((...args) => {
//logic to update the state...
});
}), setClassRoles); //call a function after the state value has updated
}
setClassRoles = () => {
this.state.classRoles.forEach((...args) => {
//your code...
});
EventEmitter.publish('currentlyEnrolled', this.state.classRoles)
}

JavaScript - replace setTimeout with async / await

First, I know this is a common question. I'm trying to get a handle on how to use async / await in place of setTimeouts, but all the examples I see online use a setTimeout to simulate the async. This throws me off when it's a set timeout that I'm trying to replace.
In the function below, I want this.filteredResultsto await the results of an API call before trying to filter those results and assign it to this.filteredResults.
getResults() {
let allResults= airtableQuery.getTable("Transfers"); // API call using imported 'getTable' function
console.log(allResults); // returns full array ▶[] although it's not available for filtering yet.
setTimeout(() => { // I want to replace this timeout
this.filteredResults = allResults.filter(
(result) => result.fields.User === "dev"
);
}, 250); // random ms that is roughly how long airtableQuery takes for the API call.
},
And the airtableQuery:
getTable(table) {
let recordsArr = [];
base(`${table}`)
.select({
maxRecords: 8000,
})
.eachPage(
function page(records, fetchNextPage) {
records.forEach((record) => {
recordsArr.push(record);
});
fetchNextPage();
},
function done(err) {
if (err) {
this.$toasted.error(err);
}
}
);
return recordsArr;
},
Please make the outer function an async function and then await the results before filtering them.
async function getResults() {
let allResults = await airtableQuery.getTable("Transfers");
this.filteredResults = allResults.filter(
(result) => result.fields.User === "dev"
);
},
Given that getTable() is not a Promise, await will not do anything. For that reason, we can make getTable() return a Promise which will resolve with recordsArr.
getTable(table) {
return new Promise((resolve, reject) => {
let recordsArr = [];
base(`${table}`)
.select({
maxRecords: 8000,
})
.eachPage(
function page(records, fetchNextPage) {
records.forEach((record) => {
recordsArr.push(record);
});
fetchNextPage();
},
function done(err) {
if (err) {
this.$toasted.error(err);
reject(err)
}else {
resolve(recordsArr)
}
}
);
})
}
Hope it helps.
i always likes primise,this my code show you
getTable(table) {
return new Promise((res, rej) => {
let recordsArr = [];
base(`${table}`)
.select({
maxRecords: 8000,
})
.eachPage(
function page(records, fetchNextPage) {
records.forEach((record) => {
recordsArr.push(record);
});
fetchNextPage();
res(recordsArr)
},
function done(err) {
if (err) {
this.$toasted.error(err);
rej(err)
}
}
);
})
}
getResults() {
airtableQuery.getTable("Transfers").then(res => {
let allResults = res
console.log(allResults);
this.filteredResults = allResults.filter(
(result) => result.fields.User === "dev"
);
});
}

async issues with js generator and promises not returning result

I'm having yet another async issue where I'm lost and have no idea where or how to fix it. Forgive my bad naming.
api call to twitch api and returns an array its results.
exports.batchPromiseWrapper = function(arr) {
const filteredMungedDataArr = [];
let promiseBatachArray = arr.map(vod_id => {
var url = `https://api.twitch.tv/kraken/videos/${vod_id.id}/markers`;
var params = { api_version: 5 };
return axios
.get(url, {
params: params,
headers: {
"Client-ID": "xxxxxxxxxxxxxxx"
}
})
.then(res => {
return res.data;
})
.catch(function(error) {
console.log(error);
});
});
return Promise.all(promiseBatachArray)
.then(markers => {
if (markers !== null) {
markers.map(markerObj => {
if (markerObj.markers.game_changes !== null) {
markerObj.markers.game_changes.forEach(gameName => {
if (gameName.label === "Fortnite") {
filteredMungedDataArr.push(markerObj);
}
});
}
});
return filteredMungedDataArr;
}
})
.catch(err => {
if (err.status === 500 || err.status === 404) {
console.log("error: ", err, err.message);
}
});
};
The data looks like this:
[[1,2,3,4,5],[1,2,3,4,5]], generator will yield and make a promise.all call of 5 before pausing 5sec and continuing to the next batch of 5.
exports.batchFetchingGeneratorWrapper = function(generator, batchArray) {
let evalNextValue = generator.next();
let delay = (v, t) => {
return new Promise(resolve => {
setTimeout(resolve.bind(null, v), t);
});
};
if (!evalNextValue.done) {
exports.batchPromiseWrapper(evalNextValue.value).then(data => {
let newBatchArray = batchArray;
if (data !== undefined) {
newBatchArray = batchArray.concat(data);
}
delay(5000).then(() => {
exports.batchFetchingGeneratorWrapper(generator, newBatchArray);
});
});
} else {
console.log("yay done!", batchArray);
return batchArray;
}
};
I'm able to console the results in batchArray from batchFetchingGeneratorWrapper, but I unable to act on it and I know it has something to do with async and how it has yet to be resolved.
promiseDataWrapper
.then(data => {
return gatherData.cleanUpVODData(data);
})
.then(data => {
function* batchFetching(batchArray) {
for (let i = 0; i < batchArray.length; i++) {
yield batchArray[i];
}
}
let batchArrResult = [];
let g = batchFetching(data);
new Promise((resolve, reject) => {
gatherData.batchFetchingGeneratorWrapper(g, batchArrResult);
if (g.done) { // i dont think this works
console.log("batchArrResult 1: ", batchArrResult);
resolve(batchArrResult);
}
}).then(result => console.log("asdfasdf", batchArrResult)); // empty array is returned
});
As far as I can tell, the problem lies chiefly in batchFetchingGeneratorWrapper().
It should be a matter of :
fixing delay()
making appropriate returns to make the recursion work
ensuring that the function returns Promise.
Almost undoubtedly (syntactically) simpler with async/await but here it is with old-fashioned thens :
exports.batchFetchingGeneratorWrapper = function(generator, batchArray) {
let evalNextValue = generator.next();
let delay = (t) => {
return new Promise(resolve => {
setTimeout(resolve, t);
});
};
if (!evalNextValue.done) {
return exports.batchPromiseWrapper(evalNextValue.value).then(data => {
return delay(5000).then(() => {
return exports.batchFetchingGeneratorWrapper(generator, batchArray.concat(data || []));
});
});
} else {
console.log("yay done!", batchArray);
return Promise.resolve(batchArray); // <<< promise wrapped to ensure that batchFetchingGeneratorWrapper() returns Promise
}
};
And chain the batchFetchingGeneratorWrapper() call appropriately :
promiseDataWrapper
.then(data => gatherData.cleanUpVODData(data))
.then(data => {
function* batchFetching(batchArray) {
for (let i = 0; i < batchArray.length; i++) {
yield batchArray[i];
}
}
return gatherData.batchFetchingGeneratorWrapper(batchFetching(data), []).then(batchArrResult => {
console.log('batchArrResult: ', batchArrResult);
return batchArrResult;
});
}).catch(error => {
console.log(error);
});

ApolloClient timeout best option

I came up with this way of doing network operations with ApolloClient but the problem is that the code looks very ugly and difficult to read, considering I have to write dozens of queries like this, it becomes tiresome and unmaintainable.
I haven't found anything in the Apollo docs or the actual code to configure the timeout.
let query = gql`
query ... {
}`;
let x = 0;
let timer = setTimeout(() => {
if (x === 0) {
console.log('error');
}
x = 1;
}, 3000);
ApolloClient.query({ query }).then(({data}) => {
clearTimeout(timer);
if (x === 0) {
if (data.result) {
console.log(data.result)
} else {
console.log('error');
}
}
}).catch((error) => {
clearTimeout(timer);
console.log('error')
});
Is there a better way of achieving the same result with less and simpler code?
Turns out, you can override the method:
export async function query(request) {
const options = {...this._opts};
return new Promise((resolve, reject) => {
setTimeout(() => reject('Network timed out'), 1e4); // 10 sec
return this.applyMiddlewares({
request,
options
}).then((rao) => {
return this.fetchFromRemoteEndpoint.call(this, rao);
}).then(response => this.applyAfterwares({
response: response,
options
})).then(({response}) => (response).json()).then((payload) => {
resolve(payload);
}).catch((e) => {
reject(e);
});
}).catch((e) => {
console.log(e);
return null;
});
}

Categories