Unable to syncronize the functions - javascript

I'm trying to execute the functions one by one in synchronization.
var subtasks = ['Site', 'Draw', 'Material', 'Conduction', 'Cable', 'Install', 'Foundation']
function clickMe() {
return new Promise(resolve => {
jQuery("#addtoptasksubmit").trigger("click"); // triggering the button click
resolve("done click");
});
}
function typeWord(word) {
return new Promise(resolve => {
jQuery("#todotask").val(word); // input
resolve("done type");
});
}
function createSubTask() {
return new Promise(res => {
jQuery('#todotask').focus();
res("done")
})
};
function startLoop(i) {
new Promise(resolve => {
var promise = createSubTask();
promise.then(resolve => {
var typePromise = typeWord(subtasks[i]);
typePromise.then((resolve) => {
var clickPromise = clickMe();
clickPromise.then((resolve) => {
console.log(resolve);
});
});
});
})
}
let i = 0;
let prom = startLoop(i);
prom.then((res) => {
startLoop(i++);
})
code is not working properly and also I wanted to increment i automatically. For loop is a no show.
I've tried for loop and recursive async function on chrome.

Doesn't your startLoop(i) function need a return statement for the new Promise() call? I have to imagine this:
// prom = undefined as startLoop never returns anything
let prom = startLoop(i);
Change your code like so:
// Current code from description
function startLoop(i) {
new Promise(resolve => {
// Fixed code
function startLoop(i) {
return new Promise(resolve => {

var subtasks = ['Site', 'Draw', 'Material', 'Conduction', 'Cable', 'Install', 'Foundation'];
function clickMe() {
return new Promise(resolve => {
setTimeout(() => {
jQuery("#addtoptasksubmit").trigger("click");
resolve("done click");
}, 1000);
});
}
function typeWord(word) {
return new Promise(resolve => {
jQuery("#todotask").val(word);
resolve("done type");
});
}
function createSubTask() {
return new Promise(res => {
jQuery('#todotask').focus();
res("done");
})
};
function startLoop(i) {
return new Promise(res => {
var promise = createSubTask();
promise.then(
(resolve) => {
var typePromise = typeWord(subtasks[i]);
typePromise.then((resolve) => {
console.trace(resolve);
var clickPromise = clickMe();
clickPromise.then((resolve) => {
console.trace(resolve);
res("done loop " + subtasks[i]);
});
});
}
);
})
}
var _index_ = 0;
var _how_ = setInterval(() => {
if (_index_ < subtasks.length) {
let loopPromise = startLoop(_index_);
loopPromise.then((resolve) => {
_index_ += 1;
});
} else {
console.log("all done go get the new task");
clearInterval(_how_);
}
}, 10000);
I can optimise it further....

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())

Create a Promise that resolves when variable is not undefined

I'm trying to Create a Promise that resolves when variable is not undefined.
Code example
https://codesandbox.io/s/quizzical-feynman-ktvox?file=/src/index.js
let fetchedPromise = new Promise((resolve, reject) => {
const check = ()=>{
setTimeout(() =>{
console.log("checking")
if (dataFetched) resolve(dataFetched);
else check()
}, 100);
}
check()
});
const waitForDataFromAnotherComponent = async () => {
let result = await fetchedPromise;
console.log("Result: ", result);
};
const assignData = () => {
setTimeout(() => {
dataFetched = 1000;
console.log(dataFetched);
}, 5000)
};
waitForDataFromAnotherComponent();
assignData();
This works but I find it inefficient as it's callstack prone and seems wrong.
Other non-working solutions I've tried:
//-------------SOLUTION 1
let fetchedPromise = new Promise((resolve, reject) => {
const check = ()=>{
if (dataFetched) resolve(dataFetched);
else check()
}
check()
});
//--------------------SOLUTION 2
let fetchedPromise = new Promise((resolve, reject) => {
if (dataFetched) resolve(dataFetched);
});
Scenario
I need a function like solution 3 that doesn't rely on setTimeout
Solved by using Javascript Proxy
Basically I assign a Proxy Object to dataFetched that listens to changes.
I re-create the function of listening due to the fact that it must include resolve()
let dataFetched
let x = {
aListener: function (val) {},
set a(val) {
dataFetched = val;
this.aListener(val);
},
get a() {
return dataFetched;
},
registerListener: function (listener) {
this.aListener = listener;
}
};
let fetchedPromise = new Promise((resolve, reject) => {
x.registerListener(function (val) {
console.log("yeyyyyyyyyyyyyyyy");
if (dataFetched) resolve(dataFetched);
});
});
const waitForDataFromAnotherComponent = async () => {
let result = await fetchedPromise;
console.log("Result: ", result);
};
const assignData = async () => {
await new Promise((resolve, reject) =>
setTimeout(() => {
x.a = 1000;
console.log(dataFetched);
resolve(dataFetched);
}, 1000)
);
};
waitForDataFromAnotherComponent();
assignData();
EDIT
Actually it's possible to externalize the resolve() function of the promise but with some downsides as stated here
example
let dataFetched
var promiseResolve, promiseReject;
let x = {
aListener: function (val) {
if (dataFetched) promiseResolve(dataFetched);
},
set a(val) {
dataFetched = val;
this.aListener(val);
},
get a() {
return dataFetched;
},
registerListener: function (listener) {
this.aListener = listener;
}
};
let fetchedPromise = new Promise((resolve, reject) => {
promiseResolve = resolve;
promiseReject = reject;
});

Nested, asynchronous promises: how to know when they're all resolved?

I'm doing some api calls from a web app. First I'm getting my partner details (a group of hotels). This partner has some properties. For each of these properties, I need to get their rooms; then for each of these rooms, I need to get their availabilities and bookings.
I would like to perform all these calls asynchronously (ie as soon as I have the room info of a property, I can get their bookings and availabilities, without waiting to have the details of all the properties).
I would like to know when everything is loaded. Below is a simplified code using timeouts to simulate api calls.
I've tried to push each new promise in an array, and use Promise.all on this array, but I run into the same issue.
I've also tried to increment a counter everytime a query is made, and decrease the counter everytime one is resolved; this is working but doesn't seem very clean?
const getPartner = () => {
const p = new Promise((resolve) => {
setTimeout(() => {
console.log('getPartner finished');
resolve({
properties: [1, 2, 3],
});
}, 1000);
});
return p;
}
const getRooms = () => {
const p = new Promise((resolve) => {
setTimeout(() => {
console.log('getRooms finished');
resolve([1, 2, 3]);
}, 1000);
});
return p;
}
const getAvailabilities = () => {
const p = new Promise((resolve) => {
setTimeout(() => {
console.log('getAvailabilities finished');
resolve([1, 2, 3]);
}, 1000);
});
return p;
}
const getBookings = () => {
const p = new Promise((resolve) => {
setTimeout(() => {
console.log('getBookings finished');
resolve([1, 2, 3]);
}, 1000);
});
return p;
}
function main() {
getPartner().then((partner) => {
Promise.all([
partner.properties.forEach((property) => {
getRooms().then((rooms) => {
rooms.forEach((room) => {
getAvailabilities();
getBookings();
})
});
})
]).then(() => {
console.log('all finished');
});
});
}
main();
I expect "all finished" to show last in the console. Instead it shows immediately after "getPartner finished"
Edit: here's what I tried with a counter:
const promises = [];
const getPartner = () => {
const p = new Promise((resolve) => {
setTimeout(() => {
console.log('getPartner finished');
resolve({
properties: [1, 2, 3],
});
}, 1000);
});
promises.push(p);
return p;
}
const getRooms = () => {
const p = new Promise((resolve) => {
setTimeout(() => {
console.log('getRooms finished');
resolve([1, 2, 3]);
}, 1000);
});
promises.push(p);
return p;
}
const getAvailabilities = () => {
const p = new Promise((resolve) => {
setTimeout(() => {
console.log('getAvailabilities finished');
resolve([1, 2, 3]);
}, 1000);
});
promises.push(p);
return p;
}
const getBookings = () => {
const p = new Promise((resolve) => {
setTimeout(() => {
console.log('getBookings finished');
resolve([1, 2, 3]);
}, 1000);
});
promises.push(p);
return p;
}
function main() {
getPartner().then((partner) => {
partner.properties.map((property) => {
getRooms().then((rooms) => {
getAvailabilities();
getBookings();
})
})
})
.then(() => {
Promise.all(promises).then(() => {
console.log('all finished');
});
});
}
main();
Several issues:
forEach does not return anything, yet you should return an array -- to feed to Promise.all.
Use Promise.all in every case where you have multiple promises
Return the promises whenever you need to chain one in a then callback
Here is how it would work:
function main() {
getPartner().then((partner) => {
return Promise.all(partner.properties.map((property) => {
return getRooms().then((rooms) => {
return Promise.all(rooms.map((room) => {
return Promise.all([getAvailabilities(), getBookings()]);
}))
});
})).then(() => {
console.log('all finished');
});
});
}

mergePromise(...).then is not a function

When I run the code, I get the error
mergePromise(...).then is not a function.
I want to know why I got this error.
const timeout = ms => new Promise((resolve, reject) => {
setTimeout(() => {
resolve();
}, ms);
});
const ajax1 = () => timeout(2000).then(() => {
console.log('1');
return 1;
});
const ajax2 = () => timeout(1000).then(() => {
console.log('2');
return 2;
});
const ajax3 = () => timeout(2000).then(() => {
console.log('3');
return 3;
});
const mergePromise = ajaxArray => {
const data=[];
ajaxArray[0]().then(i=>data.push(i));
timeout(1005).then(() => {
ajaxArray[1]().then(i=>data.push(i));
});
timeout(10).then(() => {
ajaxArray[2]().then(i=>data.push(i));
});
return data;
};
I guess maybe the timeout function has some mistake. What am I doing wrong?
Maybe you can try return Promise.resolve(data) instead, it would return a promise, which is what you need.

Put on hold async loop then continue processing

I want to find out if there is better way to do this code. I'm trying to process two files and save on the database. I would like to process a an Order (parent) and when it's completed then processed the child records. If the DB is locking some records I wait 2 secs then try again.
I got it working this way, but I would like to know how can I make it better.
P.S. I cannot use async - await
var orderItems = [1, 2, 3];
var tries = 0;
saveOrder()
.then(function() {
console.log('Done Order');
try {
asyncLoop(orderItems.length, nextItem, success);
}
catch(e) {
console.log(e);
}
})
.catch ( console.log );
function nextItem(loop) {
saveItems(loop.iteration())
.then((msg) => {
console.log(loop.iteration());
loop.next();
})
.catch((e) => {
if (e instanceof String) console.log('Catched !!');
console.log(e);
tries = 1;
waitNTryAgain().then(() => { console.log('Trying again!'); nextItem(loop); });
});
}
function waitNTryAgain() {
return new Promise((resolve, reject) => {
setTimeout( resolve, 2000, 'Done waiting');
});
}
function success() {
console.log('Done asyncLoop!');
}
function saveOrder() {
return new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'Save Order Done!');
});
}
function saveItems(itemNumber) {
return new Promise((resolve, reject) => {
if (itemNumber == 1 && tries == 0) {
setTimeout(reject, 4000, 'DbLockedException');
}
else {
setTimeout(resolve, 4000, 'Save Item#: ' + itemNumber + ' Done!');
}
})
}
function asyncLoop(iterations, func, callback) {
var index = 0;
var done = false;
var loop = {
next: function() {
if (done) return;
if (index < iterations) {
index++;
func(loop);
}
else {
done = true;
callback();
}
},
iteration: function() {
return index - 1;
},
break: function() {
done = true;
callback();
}
};
loop.next();
return loop;
}
The best I could do to improve would be to create a module pattern:
var AsyncProc = (function(){
return{
orderItems : [1, 2, 3],
tries : 0,
init : function()
{
this.saveOrder()
.then(() => {
console.log('Done Order')
try
{
this.asyncLoop(this.orderItems.length, this.nextItem.bind(this), this.success)
}
catch(e) { console.log(e) }
})
.catch( console.log );
},
saveOrder : function()
{
return new Promise((resolve, reject) =>{
setTimeout(resolve, 2000, 'Save Order Done!')
})
},
nextItem : function(loop)
{
this.saveItems( loop.iteration() )
.then((msg) => {
console.log(loop.iteration())
loop.next();
})
.catch((e) =>{
console.log(e);
this.tries = 1;
this.waitNTryAgain().
then(() => { console.log('Trying again!'); this.nextItem(loop); })
})
},
waitNTryAgain : function()
{
return new Promise((resolve, reject) => {
setTimeout( resolve, 2000, 'Done waiting')
})
},
saveItems : function(itemNumber)
{
return new Promise((resolve, reject) =>{
if (itemNumber == 1 && this.tries == 0)
{
setTimeout(reject, 4000, 'DbLockedException');
}
else
{
setTimeout(resolve, 4000, 'Save Item#: '+itemNumber+' Done!');
}
});
},
success : function()
{
console.log('Done asyncLoop!')
},
asyncLoop : function(iterations, func, callback)
{
var index = 0;
var done = false;
var loop =
{
next: function()
{
if (done) return;
if (index < iterations)
{
index++;
func(loop);
}
else
{
done = true;
callback();
}
},
iteration: function()
{
return index - 1;
},
break: function()
{
done = true;
callback();
}
};
loop.next();
return loop;
}
};
})();
AsyncProc.init();
The problem with you code – you are implementing asyncLoop by yourself. It's better to use some library for it.
You can do it with https://github.com/caolan/async or http://bluebirdjs.com/docs/api
I prefer bluebird. It'll also give you some better way to handle errors.

Categories