How to defer long-time simple function? - javascript

I create microservice and in one function I have three other functions, for example:
functionA();
functionB();
functionC();
return json({status: processed});
All functions are synchronous, but they execute Math operations. functionB is the longest performed, so I would like to use it as for example HTTP request, which is asynchronous.
I tried:
functionB() {
return new Promise(//etc...);
}
and
async functionB() {
return 1;
}
but my function still is synchronous.
How does Node recognize which function can be run immediately or should go to event loop? Why Promise and async not working in this case?

This logs 'foo' then 'bar'
function foobar() {
var p = Promise.resolve();
p.then(() => console.log('bar'));
console.log('foo');
return p;
}
While this logs 'bar' then 'foo'.
function foobar() {
var p = new Promise((resolve, reject) => {
console.log('bar');
resolve();
})
console.log('foo');
return p;
}
This is because the callback (resolve, reject) => ... passed to new Promise is called immediately as part of the promise creation process, thus the callback is actually a sync function.
Similarly with async function.
async function B() {
return 1;
}
Marking a sync function async doesn't magically make it "async". If the function body (return 1 in this example) consists of all synch operations, then it is the same as the callback passed to new Promise, it's still executed synchronously when called.
If you really need to defer the task to next loop iteration, use setTimeout(cb) or setImmediate(cb) is more promising. That cb is async for sure.

Related

JavaScript wrap existing function in async one: deal with the result (automatically wrapped into a Promise)?

I'm trying to write a "mixing" for JavaScript classes (controllers, in my app) to automatically "await" for a given function to be resolved, before actually invoke the real methods. Real class methods should receive the resolved value as last argument.
Here is the code of useAwait, where i'm looking for the static class property awaits and wrapping the originalFunc into a new async one. I'm calling the new function passing the original arguments plus the asyncFn call result:
const useAwait = (controller, asyncFn) => {
controller.constructor.awaits.forEach(func => {
const originalFunc = controller[func];
controller[func] = async (...args) => {
return originalFunc.apply(
controller,
[...args, await asyncFn.call(controller)]
);
};
});
}
So when useAwait(ctrl, this.load) is invoked on an instance this class:
class Controller {
static awaits = ['foo', 'bar'];
promise;
constructor() {
useAwait(this, this.load);
}
async foo(e, resolved) {
return resolved;
}
bar(resolved) {
return resolved;
}
async load() {
if (!this.promise) {
this.promise = new Promise(resolve => setTimeout(() => {
resolve('Hello World!');
}, 3000));
}
return this.promise;
}
}
The problem: all seems fine for foo (already async), but it's not for bar: the result is a Promise because now the bar is wrapped in async (wan't before). I know that an async function result is wrapped into a Promise. Codepen example where bar call outputs "[object Promise]".
So the question is: in theory, I should check if the original function is async and if it was not, await for it's return value?
...in theory, I should check if the original function is async and if it was not, await for it's return value?"
It wouldn't matter, your wrapper is async; an async function always returns a promise, whether you use await or not. Moreover, your wrapper can't be synchronous, because it needs to call awaitFn (load, in the example) and wait for its result.
If you're going to wrap originalFunction (bar) such that it waits for awaitFn (load) to complete, the wrapped version of it needs to be asynchronous (either async, or return a promise explicitly [or accept a callback, but better IMHO to use promises]). It cannot be synchronous, because awaitFn (load) isn't synchronous.
If the class instance isn't ready for use when you construct it, you might consider using a static method to get an instance instead; the static instance would return a promise that it fulfills with the instance once load is complete. Rough sketch:
class Controller {
dataFromLoadingProcess;
constructor(dataFromLoadingProcess) {
this.dataFromLoadingProcess = dataFromLoadingProcess;
}
async foo(e, resolved) {
// ...optionally use `this.dataFromLoadingProcess`...
return resolved;
}
bar(resolved) {
// ...optionally use `this.dataFromLoadingProcess`...
return resolved;
}
static async createInstance() {
await /*...the loading process...*/;
return new Controller(/*...data from loading process here, perhaps...*/)
}
}

Despite Await the function is being executed instantly

I am new to Javascript and am facing trouble dealing with Async/Await. Here is my code, as per my understanding adding await puts on hold the function
Here, inside foo, it should put on hold the code at checker() and move to running the commands outside foo, but instead it executes the checker() function before console.log('the end').
function checker() {
console.log('inside checker');
return "Ok"
}
async function foo() {
let a = await checker(); // Shouldn't using await here let next line outside foo to execute
console.log("mid", a);
}
console.log(1);
foo();
console.log('the end');
// Output coming is:
//1
//inside checker
//the end
//mid Ok
Can someone please tell me what properties are making it to behave this way. I know there's something that I am missing but can't figure out what.
Your checker function is not asynchronous, but you also need to do something that is actually async within it.
At the moment, all of the promises are instantly resolved which provides no opportunity for later code to run.
We need to actually create a promise, merely defining a function as async isn't enough unless something inside is returning a promise, so we return a new promise which is resolved by the setTimeout callback.
Note that the timeout period is 0 which is enough to cause the javascript event loop to be invoked, which allows the next statement(s) after calling foo to be processed. Changing this to any positive integer will change the execution time but not the order of events.
function checker() {
return new Promise(resolve => {
setTimeout(() => resolve('Ok'), 0)
})
}
function foo() {
let a = checker();
console.log(new Date(), "mid");
return a
}
(async () => {
console.log(new Date(), 'start');
foo().then(v => console.log(new Date(), 'eventually', v));
console.log(new Date(), 'the end');
})()
You didn't define your function as async
function checker() {
console.log('inside checker');
return "Ok"
}
It should be
async function checker() {
console.log('inside checker');
return "Ok"
}
await tells your code to wait for the function to finish. If you want to continue running without waiting, then you shouldn't use the await keyword. async also needs to be on the function that you want to run asynchronously, in this case checker()
async function checker() {
console.log('inside checker');
return "Ok"
}
function foo() {
let a = checker();
console.log("mid", a);
}
console.log(1);
foo();
console.log('the end');
foo is an async function, ie the code inside it will wait if you use the await keyword
But the foo function returns a promise. so if you want to wait for foo either use
await foo();
or use
foo().then(() => { console.log('the end'); })

How do I get this if statement to finish executing before the rest of the code runs?

This is a simple version of what I'm trying to do in my application. I have an if statement which evaluates the result of a function call and then populates an array if the statement comes back as true. AFTER the if statement is completely finished, I want to run some more code such as the console.log as seen below.
I understand that the if's evaluation is taking too long to finish and javascript just continues to the console.log because of its asynchronicity. How do I make the code wait for the if statement to complete?
var tabs = [];
if (isTrue()) {
tabs.push('some string');
}
console.log(tabs[1]);
function isTrue() {
setTimeout(function() {
return true;
}, 500)
}
You can just wrap your code in a Promise and consume the returned values by calling then on it:
var tabs = [];
isTrue().then(res => {
if (res) {
tabs.push('some string');
}
return tabs;
}).then(arr => {
console.log(arr);
});
function isTrue() {
//Just wrap your existing code in a Promise constructor
return new Promise((resolve, reject) => {
setTimeout(() => {
//Pass whatever value you want to consume later to resolve
resolve(true);
}, 500)
});
}
You could pass a callback to the isTrue() function, something like:
function isTrue(_callback) {
setTimeout(function() {
// code here
// Call the callback when done
if (typeof(_callback) === 'function')
_callback(tabs);
});
}
function showTabs(tabs) {
console.log(tabs[1]);
}
isTrue(showTabs);
Ought to work.
Using modern javascript, you can achieve that using promises and async/await:
const isTrue = () => new Promise(resolve => setTimeout(resolve, 500, true));
// you can only use `await` inside an `async` function
async function main() {
// better use `let` instead of `var` since `let` is block scoped,
// see:
// <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let>
let tabs = [];
if (await isTrue()) {
tabs.push('some string');
}
// array's index start by 0, not 1
console.log(tabs[0]);
}
main();
(this code also use arrow functions for isTrue.)
isTrue() returns undefined. The return true inside of the setTimeout callback will return back to the timeout call, not to the isTrue() call. The code executes immeadiately and there is no asynchronity involved (except for that timer that does nothing).

Chain multiple AJAX calls with delay and passing variables

I'm working on a way to chain a set of 3 ajax calls per variable against an array of data with some delay in between.
Taking into account this answer.
I'm trying to update the code to achieve the following:
Add a delay in the b() and c() function
Pass a variable from a() to b() and from b() to c()
Is there a way I can pass a variable a() would generate to b() without using global variables? If not that's fine, I'd just like to know.
And how exactly can I get b() to be delayed for several seconds before processing c()? I would assume adding in a setTimeout would work as it's waiting for the promise before it starts c(), but this is not the case.
jsfiddle
function a(user, pass) {
return $.post('/echo/json/', {}, function(re){
console.log(1);
});
}
function b() {
setTimeout(function() {
return $.post('/echo/json/', {}, function(re){
console.log(2);
});
}, 3000);
}
function c() {
console.log(3);
}
var data = [{u: 'au', p: 'ap'}, {u: 'bu', p: 'bp'}];
var counter = 0;
function main() {
if(counter < data.length) {
$.when(a(data[counter].u, data[counter].p).then(b).then(c)).done(function(){
counter++;
main();
})
}
}
main();
To ensure that c() isn't executed until after the timeout code has been called, create your own promise and return it from the b() function. You should wrap the setTimeout function in this promise, and call the resolve(res) method to notify the .then() functions watching the promise, passing an object representing the data or body of the response.
function b(dataFromA) {
return new Promise((resolve, reject) => {
setTimeout(function() {
return $.post('/echo/json/', {}, res => {
let dataToB = res;
console.log(2);
resolve(dataToB);
});
}, 3000);
});
}
Note that b() now accepts data that can be passed from the response of the a() promise. You can manipulate this data inside the b(res) function or in the promiseFromA.then(res => { // ... Your promise callback code }); before calling b(res).
setTimeout as used in function b is not a promise. i will find some docs to site and post shortly but here is what i see.
to use a promise you need to call a promise method, setTimeout is not a promise. it is only a delay. it has to do with the event loop in javascript or in the javascript runtime to be more correct. there is some good stuff over here --> https://github.com/getify/You-Dont-Know-JS/tree/master/async%20%26%20performance
also .then only works to resolve a promise
getify really breaks it down but i would start with the javascript event loop

Calling function with a Promise hangs when in a loop

When you run the following javascript code, it works fine. But if you remove the setTimeout function call and replace it with a line of code like:
resolve(x);
the browser will hang.
The browser appears to hang because it is processing the calls to processNode function in an endless while loop. But what isn't clear is why there is any blocking going on at all. processNode returns a Promise. Furthermore, the startNodeProcessing is an async function that is using await on the calls. I thought that by having a Promise and async function with await would prevent any blocking of the thread, but clearly I'm wrong. It appears that the setTimeout just executes its code on a separate thread thus preventing blocking. But if this is the case, why bother with a Promise or async function to start with?
function processNode(x) {
return new Promise(resolve => {
console.log("X: " + x + " " + Date.now());
setTimeout(() => {
resolve(x);
}, x);
});
}
async function startNodeProcessing() {
while(true) {
var a = processNode(1);
var b = processNode(1);
var c = processNode(1);
var d = processNode(1);
var a1 = await a;
var b1 = await b;
var c1 = await c;
var d1 = await d;
}
return;
}
startNodeProcessing();
Well the following happens:
var a = processNode(1);
//the parser jumps to processNode and creates a promise:
return new Promise(function(resolve)
//the promise is resolved
resolve(x);
//the function returns, we enter the main function again:
var a1 = await a;
//await internally calls the then function:
a1.then(return to this func)
//as the promise is resolved, the then callback is called immeadiately
//the parser returns to the main function
As you can see, the parser never exits the loop, therefore it is blocking as it never halts.
Furthermore, the startNodeProcessing is an async function that is
using await on the calls.
No, await is not used on the calls. The call is made at lines before await. See serial await requests in a return run in parallel?
It blocks without the setTimeout. Just replace setTimeout with
resolve(x) and it will block. I'm trying to understand why.
Because Promise constructor executor function is called immediately, for example, the console.log() within Promise constructor at Question is called immediately, irrespective of if or when resolve function parameter is called.
Promise(resolve => {
console.log("this is not executed asynchrously");
resolve(1)
})
Promise
Syntax
new Promise( /* executor */ function(resolve, reject) { ... } );
Parameters
executor
A function that is passed with the arguments resolve and reject. The
executor function is executed immediately by the Promise
implementation, passing resolve and reject functions (the executor is
called before the Promise constructor even returns the created
object).

Categories

Resources