How to measure the time of several calls of async function - javascript

I have a problem with understanding how do async functions in js work. So I need to call async function for 5 times and measure the duration of every execution. In the end I should have an array with 5 time values.
I have smth like this
for (let i = 0; i < 5; i++) {
const run = async () => {
await test(thisTest, filename, unitTestDict);
};
measure(run).then(report => {
// inspect
const {tSyncOnly, tSyncAsync} = report;
// array.push(tSyncAsync)
console.log(`∑ = ${tSyncAsync}ms \t`);
}).catch(e => {
console.error(e)
});
}
Here I found the realization of time measure function:
class Stack {
constructor() {
this._array = []
}
push(x) {
return this._array.push(x)
}
peek() {
return this._array[this._array.length - 1]
}
pop() {
return this._array.pop()
}
get is_not_empty() {
return this._array.length > 0
}
}
class Timer {
constructor() {
this._records = new Map
/* of {start:number, end:number} */
}
starts(scope) {
const detail =
this._records.set(scope, {
start: this.timestamp(),
end: -1,
})
}
ends(scope) {
this._records.get(scope).end = this.timestamp()
}
timestamp() {
return performance.now()
}
timediff(t0, t1) {
return Math.abs(t0 - t1)
}
report(scopes, detail) {
let tSyncOnly = 0;
let tSyncAsync = 0;
for (const [scope, {start, end}] of this._records)
if (scopes.has(scope))
if (~end) {
tSyncOnly += end - start;
tSyncAsync += end - start;
const {type, offset} = detail.get(scope);
if (type === "Timeout")
tSyncAsync += offset;
}
return {tSyncOnly, tSyncAsync}
}
}
async function measure(asyncFn) {
const stack = new Stack;
const scopes = new Set;
const timer = new Timer;
const detail = new Map;
const hook = createHook({
init(scope, type, parent, resource) {
if (type === 'TIMERWRAP') return;
scopes.add(scope);
detail.set(scope, {
type: type,
offset: type === 'Timeout' ? resource._idleTimeout : 0
})
},
before(scope) {
if (stack.is_not_empty) timer.ends(stack.peek());
stack.push(scope);
timer.starts(scope)
},
after() {
timer.ends(stack.pop())
}
});
return await new Promise(r => {
hook.enable();
setTimeout(() => {
asyncFn()
.then(() => hook.disable())
.then(() => r(timer.report(scopes, detail)))
.catch(console.error)
}, 1)
})
}
I can call it inside the loop and get console.log with time for every iteration:
measure(run).then(report => {
// inspect
const {tSyncOnly, tSyncAsync} = report;
// array.push(tSyncAsync)
console.log(`∑ = ${tSyncAsync}ms \t`);
}).catch(e => {
console.error(e)
});
But when I try to push this console values to array, nothing comes out, the array remains empty. Is there a way to fill it in?

Related

how to run useEffect only twice

Here is My useEffect is going in Infinite loop, becouse checkimage value is changing becouse the value is assigned in fetch(), so anyone know how to solve it. I want to get varient data with image but I can't get it in first time.
help me if you can
Thank You
useEffect(() => {
fetch({ pagination });
}, [checkimage]);
const fetch = async (params = {}) => {
if (type == 'product') {
dispatch(await ProductService.getProduct(productId))
.then((res) => {
let variantsdatas = getImageArns(res.data.variants);
getImages(variantsdatas);
let record = [];
record.push(res.data)
setVarientsData(record)
})
.catch((err) => {});
} else {
dispatch(await ProductService.getProducts())
.then((res) => {
console.info({ 'res.data': res.data });
setVarientsData(res.data.products);
setPagination({
...params.pagination,
total: res.total_count,
});
})
.catch((err) => {});
}
};
const getImageArns = (variantsdatas) => {
const variantImageArns = [];
variantsdatas.forEach((variant, index) => {
variant[index] = variant.variantId;
if (variant.variantImagesListResponseDto.images.length > 0) {
let variantImageObj = {
variantId: variant.variantId,
arnUrl: variant.variantImagesListResponseDto.images[0].docUrl,
};
variantImageArns.push(variantImageObj);
}
});
// console.info('id', variantImageArns);
return variantImageArns;
};
const getImages = async (variantsdatas) => {
const images = [];
dispatch(await ProductVariantService.getImage(variantsdatas))
.then((res) => {
console.info(res.data.fileResponseDtoList);
let presignedURLs = {};
res.data.fileResponseDtoList.map(
(i) => (
(presignedURLs = {
variantId: i.variantId,
arnUrl: i.presignedURL,
}),
console.info(presignedURLs),
images.push(presignedURLs)
)
);
setcheckimage(images);
})
.catch((err) => {
console.info('Get Error District...');
});
};
var img = 'img';
const setVarientsData = (products) => {
let varients_array = [];
if (products.length > 0) {
products.forEach((product) => {
if (product.variants.length > 0) {
let product_varients = product.variants;
product_varients.forEach((varient) => {
for (var f = 0; f < checkimage.length; f++) {
if(checkimage[f].variantId == varient.variantId){
img = checkimage[f].arnUrl;
f = checkimage.length
}
else{
img = 'img2';
}
}
varients_array.push({
image: img,
variantId: varient.variantId,
productVariantName: varient.variantName,
productName: product.productName,
brand: '-',
sellerSku: varient.productVariantCode,
status: product.status,
category: product.subCategoryInfo.categoryInfo.categoryName,
subCategoryName: product.subCategoryInfo.subCategoryName,
state: '-',
market: '-',
mrp: varient.price.amount + ' ' + varient.price.currency,
sellingPrice: '-',
manufacturer_product_variant_code:
varient.manufacturerProductVariantCode,
product_varient_code: varient.azProductVariantLongCode,
hsnCode: varient.hsnCode,
});
});
}
});
}
setVarients(varients_array);
console.info('varients_array ====>>', {varients_array})
};
I think that if I stop to run blow code getImage function then I can get my result
am I right?
But I tried It too but is also not happening properly.
a quick and dirty fix could be to work with a counter.
and only run the fetch in the useEffect, when counter is 0.
have you tried that?

How to call aysnc function getAffiliatesCodes() inside other async function

this is the first function , i have this function getAffliateCodesAsync() my requirement is to call this method from inside other function (function -2 >> generateCriBodyWithCreParameter(..))
and pass the returning value of >>(function-1) getAffliateCodesAsync(), into the third function and use that value in (function -3) checkLessorMagnitudeCode(..) and use the returning value of function-2 in function-3 at place where codeList is used, Please help
//function-1.
async function getAffliateCodesAsync(){
console.debug("==AFFILIATE_CODES==");
const ApplicationParameter = loopback.getModel('ApplicationParameter');
const applicationParamFieldValue = await ApplicationParameter.find({
where: {
fieldName: 'AFFILIATE_CODES'
},
fields: ['fieldValue']
});
return (applicationParamFieldValue.length)? applicationParamFieldValue.map(entity => String(entity['fieldValue'])):[];
}
//2.function-2
const generateCriBodyWithCreParameter = (positions, lotNumber, cutOffDate) => {
const CreParameter = loopback.getModel('CreParameter');
let creId = 1;
const positionData = [];
const content = [];
return CreParameter.find()
.then((creParameterList) => {
const promises = positions.map((position) => {
const cutOffDatePreviousMonth = getCutOffDatePreviousMonth(position.accountingDate);
return positionNativeProvider.getPositionInformationForPreviousCutOffDateForCriApf(
position, cutOffDatePreviousMonth)
.then((positionRetrieved) => {
const positionLowerCase = _.mapKeys(position, (value, key) => _.toLower(key));
const creParameters = _.filter(creParameterList, {
flowType: 'MI',
event: 'POSITION',
liabilityAmortizationMethod: position.liabilityAmortizationMethod
});
for (const creParameter of creParameters) {
const atollAmountValue = getAtollAmountValue(positionLowerCase, creParameter);
if (atollAmountValue && matchSigns(atollAmountValue, creParameter.amountSign)) {
const lineGenerated = checkContractLegalStatusForCri(position, creParameter,
atollAmountValue, content, creId, lotNumber, cutOffDate, positionRetrieved);
//No Line is generated in this case so the creId must not incremente
if (lineGenerated !== -1) {
positionData.push({
positionId: position.id,
creId
});
creId++;
}
}
}
});
});
return Promise.all(promises)
.then(() => {
return {
contentCreBody: content.join('\n'),
positionData
};
});
});
};
//function -3
const checkLessorMagnitudeCode = (lessorMagnitudeCode,codeList=[]) => {
if (!lessorMagnitudeCode) return false;
if (_.size(lessorMagnitudeCode) === 5 &&
(_.startsWith(lessorMagnitudeCode, 'S') || _.startsWith(lessorMagnitudeCode, 'T'))
&& codeList.includes(lessorMagnitudeCode)) {
return true;
}
return false;
};
//above codelist where I want to use the returning value

How to make recursive promise calls?

I am working with an API that gives me data with a limit per request (here 25). Therefore, I have to recursively make promises with fetch. However, while most of my logic works, when I try to return from the function it will return an empty array. The image below will make it more clear.
const url = (conf_name) => {
return (
"https://api.elsevier.com/content/search/scopus?view=COMPLETE&cursor=*&query=CONFNAME(" +
conf_name +
")%20AND%20DOCTYPE(cp)%20AND%20SRCTYPE(p)&field=dc:creator,dc:title,dc:description,affilname,affiliation-city,affiliation-country,authkeywords,prism:doi,prism:doi,prism:coverDate"
);
};
const savePapers = (json, conf_name) => {
let temp = new Array();
for (let i = 0; i < json["search-results"]["entry"].length; i++) {
temp[i] = {
title: json["search-results"]["entry"][i]["dc:title"],
author: json["search-results"]["entry"][i]["dc:creator"],
publication_date: json["search-results"]["entry"][i]["prism:coverDate"],
doi: json["search-results"]["entry"][i]["prism:doi"],
abstract: json["search-results"]["entry"][i]["dc:description"],
author_keywords: json["search-results"]["entry"][i]["authkeywords"],
proceeding: conf_name,
};
}
return temp;
};
async function getPapers(final, url, conf_name) {
let total_amount_of_papers;
let next;
let position = 2;
try {
let response = await fetch(url, options);
let json = await response.json();
total_amount_of_papers = json["search-results"]["opensearch:totalResults"];
if (json["search-results"]["link"][position]["#ref"] == "prev")
next = json["search-results"]["link"][position + 1]["#href"];
next = json["search-results"]["link"][position]["#href"];
final = final.concat(savePapers(json, conf_name));
if (final.length === 50) {
console.log("hey",final.length);
return final;
}
await getPapers(final, next, conf_name);
} catch (error) {
console.log(error);
}
}
const createNewConf = async (conferences) => {
let final = new Array();
try {
var temp = new Conference({
acronym: conferences.acronym,
name: conferences.fullname,
area: conferences.area,
subarea: conferences.subarea,
location: conferences.location,
url: conferences.url,
description: conferences.description,
papers: await getPapers(final, url(conferences.acronym),conferences.acronym),
});
console.log(temp.papers.length);
} catch (error) {
console.log(error);
}
return temp;
};
describe("Saving records", function () {
it("Saved records to the database", async function (done) {
var conferences = [];
try {
for (var i = 0; i <= 1; i++) {
conferences[i] = await createNewConf(json_conferences[i]);
conferences[i].save().then(function () {
assert(conferences[i].isNew === True);
done();
});
}
mongoose.connection.close();
} catch (error) {
console.log(error);
}
});
});
Below you can see the length of my final array after passing the if to stop fetching more. and the second number is what I receive in the initial call
Console
Maybe anyone has an idea of the undefined behavior that occurs during return.
Your help is much appreciated.

How to do sequential query execution?

I have such a request:
try {
/* 1) */
const dayReports = await DayReport.findAll(query);
dayReports.forEach((dayReport, index) => {
/* 2) */
const findAllYear = DayReport.findAll({
where: {
[Op.and]: [
{
report_date: {
[Op.between]: [new Date(dayReport.dataValues.report_date).getFullYear() + '-01-01', dayReport.dataValues.report_date]
}
}
]
}
});
/* 3) */
var get_sinking_year = 0;
for (var i = 0; i < findAllYear.length; i++) {
get_sinking_year += findAllYear[i].dataValues.sinking_day
}
/* 4) */
console.log(get_sinking_year)
})
} catch (e) {
errorHandler(res, e);
}
And I need to execute the request in order, as the numbers in the comments are located (I.e 1,2,3,4.).
Instead, my request is executed in this order 1,3,4,2.
Try this. It first gathers all the findAllYear results (steps 2), then executes steps 3 and 4 for each result.
try {
/* 1) */
const dayReports = await DayReport.findAll(query);
const allYearArraysPromises = [];
dayReports.forEach((dayReport, index) => {
/* 2) */
const findAllYear = DayReport.findAll({
where: {
[Op.and]: [
{
report_date: {
[Op.between]: [new Date(dayReport.dataValues.report_date).getFullYear() + '-01-01', dayReport.dataValues.report_date]
}
}
]
}
});
allYearArraysPromises.push(findAllYear);
}
const allYearArrays = await Promise.all(allYearArraysPromises);
allYearArrays.forEach((findAllYear) => {
/* 3) */
var get_sinking_year = 0;
for (var i = 0; i < findAllYear.length; i++) {
get_sinking_year += findAllYear[i].dataValues.sinking_day
}
/* 4) */
console.log(get_sinking_year)
});
} catch (e) {
errorHandler(res, e);
}
It's a little different from Tilieth's answer. If you wish to add a 5th step in the future, it would work in the correct order,
12345. With Tilieth's answer, the order would be 12534.
I'm adding some test scripts to illustrate this.
Tilieth's:
async function tilieth() {
const dayReports = await new Promise(resolve => resolve(['a', 'b', 'c']));
console.log('Step 1 - Result:', dayReports);
dayReports.forEach(async(dayReport, index) => {
console.log('Step 2 for', dayReport);
const findAllYear = await new Promise(resolve => {
setTimeout(() => {
resolve(dayReport);
}, 500);
});
console.log('Steps 3 & 4 for', findAllYear);
});
console.log('Step 5');
}
tilieth();
Mine:
async function stratubas() {
const dayReports = await new Promise(resolve => resolve(['a', 'b', 'c']));
console.log('Step 1 - Result:', dayReports);
const allYearArraysPromises = [];
dayReports.forEach((dayReport, index) => {
console.log('Step 2 for', dayReport);
const findAllYear = new Promise(resolve => {
setTimeout(() => {
resolve(dayReport);
}, 500);
});
allYearArraysPromises.push(findAllYear);
});
const allYearArrays = await Promise.all(allYearArraysPromises);
allYearArrays.forEach((findAllYear) => console.log('Steps 3 & 4 for', findAllYear));
console.log('Step 5');
}
stratubas();
You need to await the result of the query inside the loop. At the moment it's returning a promise and goes straight to the following code.
try const findAllYear = await DayReport.findAll
Try using await or promises for "DayReport.findAll()". Also use map instead of for loop.

Calling another function on same composed function with Factory functions

Is there a way to get rid of the this keyword on the line:
this.getOscillatorConfig(oscNumber);
below?:
const oscPlayer = (audioContext, voiceConfig) => ({
getOscillatorConfig(oscNumber)
{
return voiceConfig.oscillators[oscNumber];
},
getOscillator(oscNumber)
{
this.getOscillatorConfig(oscNumber);
let vco = audioContext.createOscillator();
vco.type = oscConfig.waveform;
return vco;
},
start: (vco, time, noteLength, frequency) => {
vco.frequency.value = frequency;
vco.start(time);
vco.stop(time + noteLength);
}
});
const octave = () => ({
applyPipeLength: (frequency, pipeLength) => {
return frequency / (parseInt(pipeLength, 10) / 8);
}
});
const Voice = (audioContext, voiceConfig) => {
return Object.assign(
{},
oscPlayer(audioContext, voiceConfig),
octave()
)
}
If I don't use it, I have getOscillatorConfig is undefined.
Or any other advice for how to structure this?
To be able to omit this, you have to create a function with name getOscillatorConfig that is available in the scope you want to call it:
const oscPlayer = (audioContext, voiceConfig) => {
function getOscillatorConfig(oscNumber) {
return voiceConfig.oscillators[oscNumber];
}
return {
getOscillator(oscNumber) {
getOscillatorConfig(oscNumber);
let vco = audioContext.createOscillator();
vco.type = oscConfig.waveform;
return vco;
},
start(vco, time, noteLength, frequency) {
// ...
}
};
};

Categories

Resources