A global object has its key/value (thing) is set in an async function setter(); using await. How to asynchronously read the value of thing in another async function getter();?
I'm getting undefined error because the getter(); is running before the await in setter(); completes.
let obj = {};
async function af() {
return 1;
}
(async function setter () {
obj.thing = await af();
})();
(async function getter () {
let thing = obj.thing;
})();
You should wait for setter function to finish, you're getting a race condition problem with this approach.
An example of how that would work would be:
var obj = {};
async function af() {
return 1;
}
(async function() {
await (async function setter () {
obj.thing = await af();
})();
await (async function getter () {
let thing = obj.thing;
})();
console.log(obj.thing);
})();
At the end of the function it should log 1 that is returned on af function
Related
I have an async generator function that I would like to just get the return value for without calling next a bunch of times. Right now I have something like this:
async function *getData(): AsyncGenerator<object[], object[]>
{
let results = []
let res = {};
while (true)
{
res = await apiCall(res.next);
results.push(...res.data)
if (!res.next) break;
yield res.data;
}
return results;
}
async function main()
{
const genFn = getData();
while (!(await genFn.next()).done) {}
}
Is there a better/more concise way that doesn't need the while loop?
There is not much you can do besides creating a function that does it for you to clean things up. You can use a for-await instead of a while loop though.
async function drainAsyncIterable(iterable) {
const iterator = iterable[Symbol.asyncIterator]();
while (!(await iterator.next()).done) {}
}
vs
async function drainAsyncIterable(iterable) {
for await (const _ of iterable) {}
}
How to change the value of data inside the asyncCall() and set it to the resolve value of the promise which is b.
What I wanted is that the asyncCall() will return b.
But what happen is that asyncCall() returns a Promise object.
function resolveAfter2Seconds(data) {
return new Promise(resolve => {
resolve(data);
});
}
async function asyncCall() {
let data = "a";
var result = await resolveAfter2Seconds("b");
data = result;
return data;
}
asyncCall();
Use IIFE
Making the function async will automatically have it return a Promise. You will either have to await it, or use .then to access the resolved value. IIFE stands for "Immediately Invoked Function Expression" – Tim VN
function resolveAfter2Seconds(data) {
return new Promise(resolve => {
resolve(data);
});
}
async function asyncCall() {
let data = "a";
var result = await resolveAfter2Seconds("b");
data = result;
return data;
}
(async function() {
console.log(await asyncCall())
})()
An async function will always return a Promise (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function#Return_value).
If you put a console.log(result) statement in the asyncCall() function body, you will realize that the value is actually resolved right there and can be used as you'd expect it. But as documented, the return value of an async function will always be "promisified", so you'd have to "await" that function call too.
To do that at the top (global) level, you can either use an IIFE (Immediately Invoked Function Expression):
(async () => console.log(await asyncCall()))();
or fall back to classical callback functions using Promise.then():
asyncCall().then(value => console.log(value));
Some browsers also support top level await expressions:
await asyncCall();
declaring function with async will return classic Promise.
so you have to use callbacks or await.
async function asyncCall() will return Promise not the result you want to.
asyncCall().then((data) => console.log('in data is your result'));
Async functions return a promise itself:
function resolveAfter2Seconds(data) {
return new Promise(resolve => {
return resolve(data);
});
}
async function asyncCall() {
const result = await resolveAfter2Seconds("b");
return result;
}
asyncCall().then(
data => console.log(data)
);
Let's say I have this code:
const myFunction = async => {
const result = await foobar()
}
const foobar = async () => {
const result = {}
result.foo = await foo()
result.bar = await bar()
return result
}
And I want this:
const myFunction = () => {
const result = foobar()
}
I tried to wrap foobar like this:
const foobar = async () => {
return (async () => {
const result = {}
result.foo = await foo()
result.bar = await bar()
return result
})()
}
But this still return a promise
I can't use .then in myFunction, I need that foobar returns the result variable instead a promise.
The problem is that myFunction is an async function and it will return a promise but It should return undefine I need to get rid of async in myFunction.
Edit: as Sebastian Speitel said, I want to convert myFunction to sync
Edit 2: to Shilly, I am using nightwatch for end2end test, nightwatch will call myFunction() if there are no errors in the execution of the function it will run perfectly, if there's an error then nightwatch's virtual machines will run forever instead stop, this problem happens if the called function is async.
To change an asynchronous function into a normal synchronous function you simply have to drop the async keyword and as a result all await keywords within that function.
const myFunction = async () => {
const result = await foobar();
// ...
return 'value';
};
// becomes
const myFunction = () => {
const result = foobar();
// ...
return 'value';
};
You should however keep one simple rule in mind.
You can't change a asynchronous function into a synchronous function if the return value depends on the value(s) of the resolved promise(s).
This means that functions that handle promises inside their body, but from whom the return value doesn't depend on those resolved promises are perfectly fine as synchronous functions. In most other scenarios you can't drop the asynchronous behaviour.
The following code gives you an example for your situation, assuming the return value of myFunction doesn't depend on the resolved promise.
const myFunction = () => {
const result = foobar();
result.then(data => doSomethingElse(data))
.catch(error => console.error(error));
return 'some value not dependent on the promise result';
};
If you want to learn more about promises I suggest checking out the promises guide and the async/await page.
Have you looked into using .executeAsync() and then having the promise call the .done() callback? That way it should be possible to wrap foobar and just keep either the async or any .then() calls inside that wrapper.
My nightwatch knowledge is very stale, but maybe something like:
() => {
client.executeAsync(( data, done ) => {
const result = await foobar();
done( result );
});
};
or:
() => {
client.executeAsync(( data, done ) => foobar().then( result => done( result )));
};
Any function marked with async will return a Promise. This:
const foobar = async () => {
return 7;
}
Will a return a Promise of 7. This is completely independent of wether the function that calls foobar is async or not, or uses await or not when calling it.
So, you're problem is not (only) with myFunction: is foobar using async which forces it to always return a Promise.
Now, said that, you probably can't achieve what you want. Async-Await is only syntax sugar for promises. What you're trying is to return a synchronous value from an asynchronous operation, and this is basically forbidden in javascript.
You're missing very important understanding here between the synchronous and asynchronous nature of the code.
Not every async function can be converted to synchronous function. You can use callback pattern instead of await/async, but I doubt that would be useful to you.
Instead I would recommend you just use await, as in your first code example, and leave functions as async, it shouldn't harm your logic.
Check this out
function foo(){
return 'foo'
}
function bar(){
return 'bar'
}
const foobar = () => {
return new Promise((resolve)=>{
let result = {}
result.foo = foo()
result.bar = bar()
return resolve(result)
})
}
const myFunction = () => {
const result = foobar()
let response = {}
result.then(val=>{
response = Object.assign({}, val);
return response
});
}
var test = myFunction()
console.log(test)
It's been frequently used that we initiate a variable synchronously.
const x = call_a_sync_function();
But when the initiator becomes async, there would be a problem.
const x = await call_an_async_function(); // SyntaxError: Unexpected reserved word
I tried anonymous async initiator, it's not perfect.
let x;
(async () => x = await call_an_async_function())();
export function func() {
call(x); // x would be undefined if func() is called too early.
}
Then I tried to export the function in the anonymous async initiator, failed again.
(async () => {
const x = await call_an_async_function();
export function func() { // SyntaxError: Unexpected token export
call(x);
}
)();
So, is there a better solution?
This is a special case of this problem. Asynchronous code can't be turned into synchronous. If a promise is used in an export then a promise should be exported:
const x = call_an_async_function();
export async function func() {
call(await x);
}
Once there are promises, promise-based control flow is propagated everywhere the order of execution and error handling should be maintained, up to entry point:
import { func } from '...';
(async () => {
await func();
...
})().catch(console.error);
Wrap everything into an async function,
async function getX() => {let x = await call_an_async_function()); return x;}
function func() {
call(x); // x would be undefined if func() is called too early.
}
async function main(){
let x = await getX()
func();
}
main()
Once top-level-await becomes part of ecmascript ( proposal), you wont have to wrap your await in async function and can use await at top level.
Now, we can use --harmony-top-level-await with node.
I have a nodejs library written using the async/await module. I try to consume it from a library which uses regular callbacks. Here is a sample code:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async (function() {
var resultA = await (Promise.promisify(bar));
return 111;
})
function bar(callback) {
setTimeout(callback, 2000)
}
function moo() {
var f = async.cps(foo)
f(function(err, res) {
console.log(res)
})
}
moo()
I expected console.log to print 111 but instead it prints:
{ _bitField: 0,
_fulfillmentHandler0: undefined,
_rejectionHandler0: undefined,
_progressHandler0: undefined,
_promise0: undefined,
_receiver0: undefined,
_settledValue: undefined }
btw if I inline the foo implementation in the "async.cps" line it works (but this is not an option since its an external library).
Any idea?
I've looked at the library your using, and by the look of it (there isn't much, and certainly no working samples), you're not using it correctly.
async(fn) will return a function that accepts some input values and upon execution will return a promise (Probably standard Promises/A+). Inside, it will call fn with the input parameters, and will resolve the returned promise when fn has returned.
async.cps(...) will return a function that accepts some input values and a node style callback function (function (err, res)) and upon execution will return a void (undefined). Inside, it will call fn with the input parameters, and will call the callback function when fn has returned with the appropriate values.
what your code does is create a function with async(fn), then pass this function to async.cps(..) as if you called async.cps(async(fn)), but that doesn't make any sense.
What you could do if you wanted to "convert" a promise to a node style callback function (unpromisifying!) using this library is this:
function moo() {
var f = async.cps(function() {
return await (foo())
})
f(function(err, res) {
console.log(res)
})
}
You double-asynced the foo function. Here are your options, depending on whether you can modify the declaration of foo or not:
Leave foo async, and create a function f that accepts a node-style callback using cps:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async(function() {
var resultA = await (Promise.promisify(bar));
return 111;
});
function bar(callback) {
setTimeout(callback, 1000);
}
function moo() {
var f = async.cps(function() {
return await(foo());
});
f(function(err, res) {
console.log(res);
});
}
moo();
Leave foo async, and use an async moo:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async(function() {
var resultA = await (Promise.promisify(bar));
return 111;
});
function bar(callback) {
setTimeout(callback, 1000);
}
var moo = async(function() {
try {
var res = await(foo());
console.log(res);
} catch (err) {
}
});
moo();
Make foo already cps at the declaration:
var async = require('asyncawait/async');
var await = require('asyncawait/await');
var Promise = require('bluebird');
var foo = async.cps(function() {
var resultA = await (Promise.promisify(bar));
return 111;
});
function bar(callback) {
setTimeout(callback, 1000);
}
function moo() {
foo(function(err, res) {
console.log(res);
});
}
moo();