How to wait while function is finished? - angular-services

I'm using angular 9 and I have some service that performs asynchronously and I need synchronize it. My code looks like the following:
#Injectable({
providedIn: 'root'
})
export class GoogleAuthService {
constructor() {
console.log('start initialize');
const libURL = "https://my.js";
this.loadScript(libURL)
.then(() => this.loadAuth2Library())
.then(() => this.initAuth2Client())
.then(() => {
console.log("ddd");
this.next();
})
.catch(reason => {
console.log("hasn't been initialized.", reason);
});
console.log('end initialize');
}
}
and I need to wait for when all constructor has been performed and then goes to the next step but in this case, I see in the console:
start initialize
end initialize
ddd
but I need:
start initialize
ddd
end initialize

performs asynchronously and I need synchronize it
Asynchronous functions are asynchronous for a reason. If you need to perform something after all the asynchronous calls are complete, then move it inside the last call. You cannot make something outside the asynchronous call to wait until it is complete.
In your case, whatever you wish to do after the calls should be moved inside like following
constructor() {
console.log('start initialize');
const libURL = "https://my.js";
this.loadScript(libURL)
.then(() => this.loadAuth2Library())
.then(() => this.initAuth2Client())
.then(() => {
console.log("ddd");
this.next();
console.log('end initialize');
})
.catch(reason => {
console.log("hasn't been initialized.", reason);
});
}

anything you wish to execute after those async functions should be inside the last THEN clause. This is because your code is async.
You may call a function after the line " console.log("ddd");"
and inside that function put the code you need to execute after initialization.
cheers

Related

Vue component doing async hangs at await while jest testing

I'm trying to test a component that loads data asynchronously when mounted. The component works as expected, it's just the test that's giving me issues. The component's async loadData() function hangs at await axios.get() while jest test runner is in the component.vm.$nextTick(). As a result, the checks in the $nextTick loop never pass.
Immediately after the $nextTick loop times out, the component's await statement completes and the component renders itself. axios is mocked, so it should resolve really fast. If I remove the await and just fill in a constant instead, the entire thing executes as expected.
I'm guessing that $nextTick loop is not asynchronous and it's consuming the thread, even though this is the recommended way of testing asynchronous stuff. The problem is, I don't have an onclick async handler to await: this method is called from onMount.
Unfortunately, I don't know how to make a jsFiddle of this one, so I hope this will be enough:
my component (the relevant parts)
export default {
data() { return { content: '' }; },
mounted() { this.loadDoc() }
methods: {
async loadDoc() {
const res = await axios.get('some url'); // <-- this is the line that hangs until timeout
// const res = { data: 'test data'}; // this would test just fine
this.content = res.data;
}
}
}
and my component.spec.js:
jest.mock('axios', () => ({
get: async (url) => {
return { data: 'test data' };
}
};
describe('my super test', () => {
it('renders', (done) => {
const doc = shallowMount(myComponent);
doc.vm.$nextTick(() => {
expect(doc.html()).toContain('test data'); // <-- this never matches
done();
});
});
});
I would delete, but I just spent quite some hours for something that was suggested in the docs, but not explained that it's the only way... I'm hoping somebody else finds this useful.
Using flush-promises package instead of $nextTick loop immediately "fixed" the problem
Code sample (rework of above):
describe('my super test', () => {
it('renders', async() => {
const doc = shallowMount(myComponent);
await flushPromises();
expect(doc.html()).toContain('test data'); // <-- now it works
});
});

Why does Node Js mongoose document deletion does not execute without await?

So i am novice at Node.js, and have been checking out its mongoose package. I have a mongodb collection with a document with field name = "Test Entry"
I have tried executing a .findOneAndDelete() method call on a model wrapped within a timeout, wrapped within a function.
One issue that baffles me is why this piece of code
function deleteEntry() {
setTimeout(function () {
Test_Model.findOneAndDelete({
name: "Test Entry",
});
}, 5000);
}
deleteEntry();
does not delete the entry within mongodb
whereas
function deleteEntry() {
setTimeout(async function () {
await Test_Model.findOneAndDelete({
name: "Test Entry",
});
}, 5000);
}
deleteEntry();
this one does.
will the mongoose method not execute unless there is a callback made of some kind. No matter if it's for vain?
There were mentions of something similar in the documentation . Does the actual execution of the command occur only when there is a callback/await/then ?
"Why does not calling this operation NOT trigger the task?" - I think MongoDB driver check if you passed a callback (as argument) or not, If you didn't pass callback, Instead, It return Promise. So no matter what, You operation will get executed.
Also you should handle Error in setTimeout function, Because It don't handle any error or error from any async operation.
Try this example:
let delay = ms => new Promise(ok => setTimeout(ok, ms));
async function deleteEntry() {
await delay(5000);
return Test_Model.findOneAndDelete({ name: "Test Entry" });
}
deleteEntry()
.then(result => console.log(result))
.catch(err => console.log(err));

Trigger the execution of a function if any condition is met

I'm writing an HTTP API with expressjs in Node.js and here is what I'm trying to achieve:
I have a regular task that I would like to run regularly, approx every minute. This task is implemented with an async function named task.
In reaction to a call in my API I would like to have that task called immediately as well
Two executions of the task function must not be concurrent. Each execution should run to completion before another execution is started.
The code looks like this:
// only a single execution of this function is allowed at a time
// which is not the case with the current code
async function task(reason: string) {
console.log("do thing because %s...", reason);
await sleep(1000);
console.log("done");
}
// call task regularly
setIntervalAsync(async () => {
await task("ticker");
}, 5000) // normally 1min
// call task immediately
app.get("/task", async (req, res) => {
await task("trigger");
res.send("ok");
});
I've put a full working sample project at https://github.com/piec/question.js
If I were in go I would do it like this and it would be easy, but I don't know how to do that with Node.js.
Ideas I have considered or tried:
I could apparently put task in a critical section using a mutex from the async-mutex library. But I'm not too fond of adding mutexes in js code.
Many people seem to be using message queue libraries with worker processes (bee-queue, bullmq, ...) but this adds a dependency to an external service like redis usually. Also if I'm correct the code would be a bit more complex because I need a main entrypoint and an entrypoint for worker processes. Also you can't share objects with the workers as easily as in a "normal" single process situation.
I have tried RxJs subject in order to make a producer consumer channel. But I was not able to limit the execution of task to one at a time (task is async).
Thank you!
You can make your own serialized asynchronous queue and run the tasks through that.
This queue uses a flag to keep track of whether it's in the middle of running an asynchronous operation already. If so, it just adds the task to the queue and will run it when the current operation is done. If not, it runs it now. Adding it to the queue returns a promise so the caller can know when the task finally got to run.
If the tasks are asynchronous, they are required to return a promise that is linked to the asynchronous activity. You can mix in non-asynchronous tasks too and they will also be serialized.
class SerializedAsyncQueue {
constructor() {
this.tasks = [];
this.inProcess = false;
}
// adds a promise-returning function and its args to the queue
// returns a promise that resolves when the function finally gets to run
add(fn, ...args) {
let d = new Deferred();
this.tasks.push({ fn, args: ...args, deferred: d });
this.check();
return d.promise;
}
check() {
if (!this.inProcess && this.tasks.length) {
// run next task
this.inProcess = true;
const nextTask = this.tasks.shift();
Promise.resolve(nextTask.fn(...nextTask.args)).then(val => {
this.inProcess = false;
nextTask.deferred.resolve(val);
this.check();
}).catch(err => {
console.log(err);
this.inProcess = false;
nextTask.deferred.reject(err);
this.check();
});
}
}
}
const Deferred = function() {
if (!(this instanceof Deferred)) {
return new Deferred();
}
const p = this.promise = new Promise((resolve, reject) => {
this.resolve = resolve;
this.reject = reject;
});
this.then = p.then.bind(p);
this.catch = p.catch.bind(p);
if (p.finally) {
this.finally = p.finally.bind(p);
}
}
let queue = new SerializedAsyncQueue();
// utility function
const sleep = function(t) {
return new Promise(resolve => {
setTimeout(resolve, t);
});
}
// only a single execution of this function is allowed at a time
// so it is run only via the queue that makes sure it is serialized
async function task(reason: string) {
function runIt() {
console.log("do thing because %s...", reason);
await sleep(1000);
console.log("done");
}
return queue.add(runIt);
}
// call task regularly
setIntervalAsync(async () => {
await task("ticker");
}, 5000) // normally 1min
// call task immediately
app.get("/task", async (req, res) => {
await task("trigger");
res.send("ok");
});
Here's a version using RxJS#Subject that is almost working. How to finish it depends on your use-case.
async function task(reason: string) {
console.log("do thing because %s...", reason);
await sleep(1000);
console.log("done");
}
const run = new Subject<string>();
const effect$ = run.pipe(
// Limit one task at a time
concatMap(task),
share()
);
const effectSub = effect$.subscribe();
interval(5000).subscribe(_ =>
run.next("ticker")
);
// call task immediately
app.get("/task", async (req, res) => {
effect$.pipe(
take(1)
).subscribe(_ =>
res.send("ok")
);
run.next("trigger");
});
The issue here is that res.send("ok") is linked to the effect$ streams next emission. This may not be the one generated by the run.next you're about to call.
There are many ways to fix this. For example, you can tag each emission with an ID and then wait for the corresponding emission before using res.send("ok").
There are better ways too if calls distinguish themselves naturally.
A Clunky ID Version
Generating an ID randomly is a bad idea, but it gets the general thrust across. You can generate unique IDs however you like. They can be integrated directly into the task somehow or can be kept 100% separate the way they are here (task itself has no knowledge that it's been assigned an ID before being run).
interface IdTask {
taskId: number,
reason: string
}
interface IdResponse {
taskId: number,
response: any
}
async function task(reason: string) {
console.log("do thing because %s...", reason);
await sleep(1000);
console.log("done");
}
const run = new Subject<IdTask>();
const effect$: Observable<IdResponse> = run.pipe(
// concatMap only allows one observable at a time to run
concatMap((eTask: IdTask) => from(task(eTask.reason)).pipe(
map((response:any) => ({
taskId: eTask.taskId,
response
})as IdResponse)
)),
share()
);
const effectSub = effect$.subscribe({
next: v => console.log("This is a shared task emission: ", v)
});
interval(5000).subscribe(num =>
run.next({
taskId: num,
reason: "ticker"
})
);
// call task immediately
app.get("/task", async (req, res) => {
const randomId = Math.random();
effect$.pipe(
filter(({taskId}) => taskId == randomId),
take(1)
).subscribe(_ =>
res.send("ok")
);
run.next({
taskId: randomId,
reason: "trigger"
});
});

Proper way to run asynchronous function in a Promise

I am making a test app using systeminformation. I'm trying to make it so that each then waits for the previous function to finish. The problem I'm having is that the functions I am running inside are also promises, so the next then runs before the function finishes.
const si = require('systeminformation');
var cpuObj;
function initCPU() {
return new Promise(resolve => {
si.cpu()
.then(data => cpuObj = data)
.catch(err => console.log(err))
.then(() => {
setTimeout(() => console.log("timer"), 3000);
})
.then(() => {
si.cpuTemperature().then(data => console.log(data));
})
.then(() => {
console.log("here");
});
});
}
function test() {
console.log(cpuObj);
}
initCPU().then(() => {
test();
});
Output:
here
{ main: -1, cores: [], max: -1 }
timer
Expected Output:
{ main: -1, cores: [], max: -1 }
timer
here
A few points that need to be addressed:
setTimeout() does not return a promise, so you need to promisify and return it.
Flatten your chain by returning the promises from within each of the continuations rather than attempting to chain continuations within other continuations (i.e. then() inside of then()).
Do not wrap the continuation chain with a promise constructor, as the chain itself is already a promise, just return it directly instead. This is considered an antipattern.
Do not use globals, because it makes the initCPU() no longer re-entrant safe. Multiple calls to initCPU() before the promise returned by the first call resolves will result in unexpected behavior otherwise. Instead, use the appropriate scope to pass values along, which in this case is the function itself.
Allow errors to propagate to the caller and let the caller decide how to handle the error. Do not handle errors from within initCPU() unless you expect to use a fallback and continue to provide meaningful data to the caller.
const si = require('systeminformation');
const delay = ms => new Promise(resolve => { setTimeout(resolve, ms); });
function initCPU() {
// use local scope, not global
let cpuObj;
// return this promise chain directly
return si.cpu()
.then(data => {
cpuObj = data;
// return the promise to the chain
return delay(3000);
})
// let caller handle errors
// .catch(err => console.log(err))
// flatten your chain
.then(() => {
console.log('timer');
// return the promise to the chain
return si.cpuTemperature();
})
// flatten your chain
.then(data => {
console.log(data);
console.log('here');
// pass data to caller
return cpuObj;
});
}
function test(cpuObj) {
// received from last continuation of initCPU()
console.log(cpuObj);
}
initCPU()
.then(test)
// handle error from caller
.catch(err => {
console.log(err);
});
If you just want to query the cpu object immediately, and query cpuTemperature after 3 seconds, I'd do something like this using Promise.all():
// default to 3 seconds, allow it to be configurable
function initCPU(ms = 3000) {
return Promise.all([
si.cpu(),
delay(ms).then(() => si.cpuTemperature())
]).then(([cpu, cpuTemperature]) => ({
cpu,
cpuTemperature
}));
}
function test (obj) {
console.log(obj.cpu);
console.log(obj.cpuTemperature);
}
initCPU()
.then(test)
.catch(err => {
console.log(err);
});

How to put wait in mocha nodejs

CODE -
.then (() => {
console.log("Wait");
setTimeout(function(){console.log("Wait to process")},1500);
this.timeout(2000);
})
.then(() => {
console.log("Get ABC");
return common.getApiData(url)})
Now when i run this code it logs data like -
Wait
Get ABC
Wait to process
(The it waits for the time specified above)
I want to put timeout before calling getApiData method..
Supposing you are using real promises, this is the function you should pass to then:
.then(function (value) {
var p = new Promise ();
setTimeout (function () {
p.resolve(value)
}, 2000)
return p
})
The next then will be called once the promise is resolved.

Resources