Node.js for() loop value keep increasing? - javascript

I have setup an interval and loop for batch orders,
However the batch number in for loop keeps increasing.
Here is my code
const Web3 = require('web3')
const web3 = new Web3('ws://127.0.0.1:8546')
const accounts = require('./tps.json');
const quoteInterval = 5 * 1000;
const batch = new web3.BatchRequest();
const sendTransactions = async () => {
try {
for (let i = 0; i < 100; i++) {
let account = accounts[i];
const tx = web3.eth.sendTransaction.request(
{
from: web3.utils.toChecksumAddress("0xa00ce1f7fbf8298f4163ab23de8752942bdff98e"),
to: web3.utils.toChecksumAddress(account),
gas: 21000,
gasPrice: 1000000000,
value: 1
}
)
batch.add(tx)
}
await batch.execute().then(console.log);
} catch (error) {
console.log(error);
process.exit(1)
}
};
if (web3.eth.net.isListening()) {
sendTransactions();
setInterval(() => {
sendTransactions();
}, quoteInterval);
}
i value wasn't increasing, however, sendTransactions() function is doing like 2, 3, 4 or 5 times after every interval

Where did you see that the value of i keep increasing? Did you put some console.log somewhere?
The following simplified version (with the same context operations of yours) is working fine:
async function asyncOperation(x) {
return new Promise((resolve) => {
setTimeout(() => {
console.log(x) # this always outputs 0 < x < 5
resolve()
}, 50)
})
}
const asyncFunction = async () => {
allPromises = []
for (let i = 0; i < 5; i++) {
allPromises.push(asyncOperation(i))
}
await Promise.all(allPromises)
};
setInterval(() => asyncFunction(), 500)

const quoteInterval = 5*1000;
const sendTransactions = async () => {
try {
for (let i = 0; i < 100; i++) {
console.log(i);
}
} catch (error) {
console.log(error);
}
};
sendTransactions();
setInterval(() => {
sendTransactions();
}, quoteInterval);
As per the logic, It will not go above the 100

Related

How i can call function inside function

I would like to call a function that is inside another function, that function will clear the timeout.
I have tried the following code, but without success:
async function Blast2() {
const delayTime = 1000;
const timer = (ms) => new Promise((res) => setTimeout(res, ms));
function ClearDelayTime() {
return clearTimeout(blast);
}
const blast = setTimeout(function () {
let blast =
"SELECT * FROM admin_contacts,temporary WHERE blast_status = 'sended'";
db.query(blast, async function (err, result, field) {
if (err) throw err;
loop: {
for (var i = 0; i < result.length; i++) {
console.log(result[i].telefone);
await timer(delayTime); // then the created Promise can be awaited
}
}
});
}, delayTime);
}
// I Want Call the function ClearDelayTime() inside Blast2()
Blast2().ClearDelayTime();
I've refactored your code. It now immediately returns a function that can be used to abort.
const db = {
query: (sql, callback) => callback(undefined,
[{telefone:1},{telefone:2},{telefone:3},{telefone:4},{telefone:5}])
}
function blast2() {
const delayTime = 1000
const timer = ms => new Promise(res => setTimeout(res, ms))
let sql = "SELECT * FROM admin_contacts,temporary WHERE blast_status = 'sended'";
let abort = false;
db.query(sql, (err, result) => {
if (!err) {
(async () => {
for(let i=0; i<result.length && !abort; i++) {
console.log(result[i].telefone);
await timer(delayTime);
}
})();
}
})
return () => abort = true;
}
let abortFunc = blast2();
setTimeout(abortFunc, 2500);
Your function Blast2 doesn't return anything. If you want to call a function inside it, you could return and store it using a variable, then call it.
Something like this:
const f1 = () => {
console.log('f1 called')
const f2 = () => {
console.log('f2 called')
}
return f2
}
const returnedFunction = f1()
console.log(returnedFunction())

Array construction with for loop vs .map

I want to create an array of async functions but I can't understand why it works with map but not with the for loop. Can someone explain the differences between for loop and map in this case?
async function sleep(ms) {
await new Promise((r) => setTimeout(r, ms));
}
async function logic(i) {
let time = i * 500;
await sleep(time);
console.log(`${i} finished after ${time}`);
return time;
}
function exampleConstructResultsViaMap(data) {
const tasks = data.map((date, i) => {
const task = async() => logic(i);
return task;
});
return tasks;
}
function exampleConstructResultsViaFor(data) {
const tasks = [];
let i = 0;
for (const date of data) {
const task = async() => logic(i);
tasks.push(task);
i++;
}
return tasks;
}
(async() => {
const data = ['a', 'b'];
const tasksMap = exampleConstructResultsViaMap(data);
const resultsMap = await Promise.all(tasksMap.map((p) => p()));
console.log(resultsMap); // [0, 500]
const tasksFor = exampleConstructResultsViaFor(data);
const resultsFor = await Promise.all(tasksFor.map((p) => p()));
console.log(resultsFor); // [1000, 1000]
})();
When you call logic(i) in exampleConstructResultsViaFor the loop has already finished, and i equals 2.
What you can do is use a simple for loop with let that's block scoped:
function exampleConstructResultsViaFor(data) {
const tasks = [];
for (let i = 0; i < data.length; i++) {
const task = async() => logic(i);
tasks.push(task);
}
return tasks;
}
Or create a closure:
const task = ((j) => async() => logic(j))(i);

Is there a way to convert a callback function into a generator in TypeScript/JavaScript?

I am using Axios to call an api endpoint which has a progress indicator. I would like to convert the onUploadProgress to a generator.
Is there a way to convert this code
setProgress({ state: 'syncing', progress: 0 });
await axios.post(uri.serialize(parsedURI), body2, {
headers: { session_id: sessionId },
onUploadProgress: (progress) => {
setProgress({ state: 'syncing', progress: progress.loaded / progress.total });
},
});
setProgress({ state: 'syncing', progress: 1 });
Into something like this
yield { state: 'syncing', progress: 0 };
await axios.post(uri.serialize(parsedURI), body2, {
headers: { session_id: sessionId },
onUploadProgress: (progress) => {
yield { state: 'syncing', progress: progress.loaded / progress.total };
},
});
yield { state: 'syncing', progress: 1 };
the problem is in the yield inside the onUploadProgress, I was thinking there could be a way to use it like when you want to convert a callback into a promise you use
new Promise(resolve => fn(resolve));
maybe there is some valid way of doing it for generators like
new Generator(next => fn(next));
You can update a local variable in the progress handler and poll it in a loop until the request is complete. Here's a sketch:
let delay = n => new Promise(res => setTimeout(res, n));
async function request(n, onProgress) {
for (let i = 0; i < n; i++) {
onProgress(i);
await delay(200);
}
return 'response'
}
async function* requestWithProgress(result) {
let prog = 0,
prevProg = 0,
res = null;
let req = request(10, n => prog = n)
.then(r => res = r);
while (!res) {
await delay(1);
if (prog > prevProg)
yield prevProg = prog;
}
result.res = res;
}
async function main() {
let result = {}
for await (let prog of requestWithProgress(result))
console.log(prog)
console.log(result)
}
main()
Here's another option, without polling, and better return API:
function progressiveAsync(factory) {
let
resultPromise = null,
resultResolver = null,
genPromise = null,
genResolver = null,
stop = {};
resultPromise = new Promise(r => resultResolver = r);
genPromise = new Promise(r => genResolver = r);
async function* gen() {
while (true) {
let r = await genPromise;
if (r === stop) {
break;
}
yield r;
}
}
factory(
val => {
genResolver(val);
genPromise = new Promise(r => genResolver = r);
},
val => {
genResolver(stop);
resultResolver(val);
}
);
return [gen(), resultPromise];
}
//
async function testRequest(opts /* count, onProgress */) {
return new Promise(async res => {
for (let i = 0; i < opts.count; i++) {
opts.onProgress(i);
await new Promise(resolve => setTimeout(resolve, 300));
}
res('response!')
})
}
async function main() {
let [progress, result] = progressiveAsync((next, done) =>
testRequest({
count: 10,
onProgress: next
}).then(done));
for await (let n of progress)
console.log('progress', n)
console.log(await result)
}
main()

How do I wait until all requests are finished?

How could I make the sortOrder function run once the getOrders function is fully completed?
I thought using a callback, so I expect getOrders to terminate and execute the sortOrder function, but I donĀ“t know how to do that. What should I do, any sugestions?
mounted () {
this.user = this.$q.localStorage.get.item('userInfo')
axios.get(`${api.getOrders}${this.user.cpf}`).then(response => {
this.orders = response.data
if (this.orders !== '') {
this.$q.loading.show()
this.getOrders(callback => {
this.sortOrder()
})
}
})
},
methods: {
getOrders: function () {
for (let i = 0; i < this.orders.length; i++) {
axios.get(api.obterOrderInfo(this.orders[i].orderId)).then(response => {
this.orderInfo = this.orderInfo.concat(response.data)
})
}
},
sortOrder: function () {
this.orderInfo.sort(this.compare)
this.$q.loading.hide()
},
compare: function (x, y) {
return x.creationDate < y.creationDate
}
}
getOrders: function () {
// Create array of requests
const requests = [];
for (let i = 0; i < this.orders.length; i++) {
requests.push(axios.get(api.obterOrderInfo(this.orders[i].orderId)))
}
// Map array of responses to orderInfo
return Promise.all(requests).then(results => this.orderInfo = results.map(result => result.data))
},
You'll need to wrap your promises together and solve them with a Promise.all like this:
getOrders: function () {
let promises = []
for (let i = 0; i < this.orders.length; i++) {
const promise = axios.get(api.obterOrderInfo(this.orders[i].orderId)).then(response => {
this.orderInfo = this.orderInfo.concat(response.data)
})
promises.push(promise)
}
Promise.all(promises)
.then(() => {
this.sortOrder()
})
},

Use promise to delay mocha

I'm using mocha and zombie.
My goal is to load data from website <a> tags from website then query name and href. So far this is working:
const Browser = require('zombie')
const browser = new Browser()
browser.visit('page', () => {
let temp = browser.document.querySelectorAll('a selector')
for (let i = 0; i < temp.length; i++) {
browsers.push({ name: temp[i].innerHTML, url: temp[i].href })
}
delete temp
})
My next step would be using this data in testing.
const data = [{ name: 'name', url: 'test' }]
describe('test with for', () => {
for (let i = 0; i < data.length; i++) {
it(data[i].name, () => {
// test code with url of data[i]
})
}
})
The only problem I have is that data array is filled asynchronously and it has to be present at time of invoking it function.
I tryed using before but i saw that it does not make sence here (because of invoking async function don't stop code to execute and only function pased in it can depend on async data)
So I tryed to do this using Promise but it also failed.
const data = []
new Promise((resolve, reject) => {
// filing data
resolve()
}).then(() => {
describe('...', () => {
for (let i = 0; i < data.length; i++) {
it (data[i].name, () => {})
}
})
})
I looked at mocha documentation and didn't find solution :/
How should I solve this problem?
Ok i found solution, problem was my mistake i forgot to remove describe inwith my browser reading was contained that's why --delay did not work.
Running code:
const { describe, it } = require('mocha')
const { assert, expect } = chai = require('chai')
const Browser = require('zombie')
const browser = new Browser()
const browsers = []
new Promise((resolve, reject) => {
browser.visit('site', () => {
let temp = browser.document.querySelectorAll('selector')
for (let i = 0; i < temp.length; i++) {
browsers.push({ name: temp[i].innerHTML, url: temp[i].href })
}
delete temp
resolve()
})
}).then(() => {
describe('Get browser name', () => {
for (let i = 0; i < browsers.length; i++) {
it(browsers[i].name, () => {
})
}
})
run()
})

Categories