I have a simple code
async function foo() {
const b = bar()
return 2 + b
}
async function bar() {
return 2
}
(async() => {
console.log(typeof foo())
})()
and it logs object. Not NaN. How does it happen that number + object -> object?
From what I remember from + spec if one of the operands is a primitive and second is an object then object should be converted to primitive. In this case with .valueOf() method
It think it's because async functions are not resolved yet in your case, becaue there is no await. So you are getting promise objects instead of your result.
see these cases:
async function foo () {
const b = await bar() //await result
return 2 + b
}
async function bar () {
return 2
}
;(async () => {
console.log(typeof await foo()) //number
})()
async function foo () {
const b = bar() //no await
return 2 + b
}
async function bar () {
return 2
}
;(async () => {
console.log(typeof await foo()) //string
})()
The functions foo and bar return a promise, so, you're getting the type of promise (Object)
Probably you want to compare the result, so you need to wait for promise resolves the concatenation:
let result = await foo();
^
async function foo() {
const b = bar() // Here you need to wait as well.
return 2 + b; // 2 + "[object Promise]"
}
async function bar() {
return 2
}
(async() => {
let result = await foo();
console.log(result);
console.log(typeof result);
})()
Now, to get the NaN value you need to convert to number:
async function foo() {
const b = bar(); // Here you need to wait as well.
return Number(2 + b); // <- Try to conver to number
}
async function bar() {
return 2
}
(async() => {
let result = await foo();
console.log(result);
console.log(typeof result);
})()
Related
Is it or will it be possible to have an ES6 class getter
return a value from an ES2017 await / async function.
class Foo {
async get bar() {
var result = await someAsyncOperation();
return result;
}
}
function someAsyncOperation() {
return new Promise(function(resolve) {
setTimeout(function() {
resolve('baz');
}, 1000);
});
}
var foo = new Foo();
foo.bar.should.equal('baz');
Update: As others have pointed out, this doesn't really work. #kuboon has a nice workaround in an answer below here..
You can do this
class Foo {
get bar() {
return (async () => {
return await someAsyncOperation();
})();
}
}
which again is the same as
class Foo {
get bar() {
return new Promise((resolve, reject) => {
someAsyncOperation().then(result => {
resolve(result);
});
})
}
}
You can get the value by await on the caller side.
class Foo {
get bar() {
return someAsyncOperation();
}
}
async function test(){
let foo = new Foo, val = await foo.bar;
val.should.equal('baz');
}
You can only await promises, and async functions will return promises themselves.
Of course a getter can yield such a promise just as well, there's no difference from a normal value.
For the value returned by the getter, this changes nothing, since an async function returns a Promise anyway. Where this matters, is in the function, since await can only be used in an async function.
If the issue it that await is wished in the function, I would do:
get property () {
const self = this; // No closure with `this`, create a closure with `self`.
async function f () { // `async` wrapper with a reference to `self`
const x = await self.someFunction(); // Can use `await`
// the rest with “self” in place of “this”
return result;
}
return f(); // Returns a `Promise` as should do an `async get`
}
I have 3 instances of the class Foo(). Let's call them foo1, foo2 and foo3 .
By default, the propriety isReady of Foo() is false. In the constructor of Foo(), there is an asynchrousnous method that sets isReady to true. For instance, I could be setTimout with different duration. After I instantiate these 3 instance, there is function called: startMainAction() that should be called only after foo1.isReady = true and foo2.isReady = true and foo3.isReady = true
Given that the asynchronous function is undetermined, (it could be random duration), there is no way for sure the order at which the foo instances will have their propriety isReady set to true. Hence, I do not think I could use callbacks to call startMainAction .
How can that be achieved?
class Foo{
constructor(n){
this.isReady = false;
setTimeout(()=>{
this.isReady = true;
console.log('I am ready '+n);
}, Math.random()*1000)
}
}
const foo1 = new Foo(1)
const foo2 = new Foo(2)
const foo3 = new Foo(3)
function startMainAction(){
console.log('All fooes must be ready before I was called')
}
One option is to add a method which adds a callback to call once you set isReady to true:
onReady(callback) {
this.readyCallbacks.push(callback);
}
Then, with those three instances, call onReady with the resolve of a Promise, and call Promise.all on those three Promises:
const foos = [foo1, foo2, foo3];
Promise.all(foos.map(foo => new Promise(resolve => foo.onReady(resolve))))
.then(startMainAction);
class Foo {
constructor() {
this.readyCallbacks = [];
this.isReady = false;
setTimeout(() => {
this.isReady = true;
console.log('I am ready');
this.readyCallbacks.forEach(callback => callback());
}, Math.random() * 1500)
}
onReady(callback) {
this.readyCallbacks.push(callback);
}
}
const foo1 = new Foo()
const foo2 = new Foo()
const foo3 = new Foo()
function startMainAction() {
console.log('All fooes must be ready before I was called')
}
const foos = [foo1, foo2, foo3];
Promise.all(foos.map(foo => new Promise(resolve => foo.onReady(resolve))))
.then(startMainAction);
I suppose you could also pass the readyCallback in the constructor, which would result in less code, but that doesn't seem quite appropriate, because a Foo (say, foo4) may not need a readyCallback, and a readyCallback isn't necessary to create an instance, it's a handler that other parts of the code request to add to an instance. (for example, if you had two parts of the code which had to listen for the isReady of foo1, you would need something like this onReady method.)
Have the constructor method create a promise that will resolve when the condition to make the object ready happens.
Then get the promises from all of the instances and wrap them with Promise.all so they wait for all of them.
class Foo {
constructor() {
this.isReady = false;
this.isReadyPromise = new Promise(
res => setTimeout(
() => { console.log("I am ready"); this.isReady = true; res(true); },
1000 + 1000 * (Math.floor(Math.random() * Math.floor(3)))
)
)
}
}
const foo1 = new Foo(),
foo2 = new Foo(),
foo3 = new Foo();
Promise.all([ foo1.isReadyPromise, foo2.isReadyPromise, foo3.isReadyPromise ]).then(() => {
console.log("All 3 are ready")
});
You can add all of your instances of Foo into a list, an array or anything that you can iterate over. Then do something along the lines of
let foos = [foo1, foo2, foo3];
function WaitUntilReady(callback) {
let ready = true;
foreach (let foo of foos) {
if ( !foo.isReady ) {
ready = false;
break;
}
}
if ( ready ) {
callback();
} else {
setTimeout(WaitUntilReady, 100); //100 miliseconds until next check
}
}
WaitUntilReady(function() {
//every instance is ready
});
Edit: using Promises seems more fancy, not sure if it really is. I'm not that much of a javascript developer so i did not even think of using them
I know that doing this:
const resultA = await a()
const resultB = await b()
// code here
Is effectively
a().then( resultA => {
b().then( resultB => {
// code here
})
})
Basically, a() runs then b() runs. I nested them to show that both resultA and resultB are in our scope; yet both function didn't run at once.
But what about this:
const obj = {
result1: await a(),
result2: await b()
}
do a() and b() run concurrently?
For reference:
const asyncFunc = async (func) => await func.call()
const results = [funcA,funcB].map( asyncFunc )
I know here funcA and funcB do run concurrently.
Bonus:
How would you represent the object assignment
const obj = {
result1: await a(),
result2: await b()
}
using then / callbacks?
UPDATE:
#Bergi is correct in this answer, this occurs sequentially. To share a nice solution for having this work concurrently for an object without having to piece together the object from an array, one can also use Bluebird as follows
const obj2 = Bluebird.props(obj)
http://bluebirdjs.com/docs/api/promise.props.html
No, every await will stop the execution until the promise has fulfilled, even mid-expression. It doesn't matter whether they happen to be part of the same statement or not.
If you want to run them in parallel, and wait only once for their result, you have to use await Promise.all(…). In your case you'd write
const [result1, result2] = await Promise.all([a(), b()]);
const obj = {result1, result2};
How would you represent the object assignment using then / callbacks?
With temporary variables for each awaited value. Every await translates into one then call:
a().then(tmp1 => {
return b().then(tmp2 => {
const obj = {
result1: tmp1,
result2: tmp2
};
return …
});
})
If we wanted to be pedantic, we'd have to pick apart the object creation:
const tmp0 = {};
a().then(tmp1 => {
tmp0.result1 = tmp1;
return b().then(tmp2 => {
tmp0.result2 = tmp2;
const obj = tmp0;
return …
});
})
do a() and b() run concurrently?
No, they run sequentially.
The equivalent would be something like
a()
.then(result1 => b())
.then(result2 => ({result1, result2}))
I have a function that returns a promise object. This is my code
var foo = function(){
// doSomething() is a promise object
return doSomething().then(() => {
Promise.resolve('Hello');
});
};
foo().then((res) => {
console.log(res);
// res = undefined but not "Hello"
});
I thought function foo would return the promise object and I would get the string "Hello". But I get undefined. Why?
You're missing a return before Promise.resolve, so it should be
var foo = function(){
return doSomething().then(() => {
return Promise.resolve('Hello');
^^^^^^
});
};
However, actually you don't need that at all, and could just return the string Hello.
var foo = function(){
return doSomething().then(() => {
return 'Hello';
});
};
You could make it even simpler by using the concise body form of arrow function, leaving off the {}.
var foo = function(){
return doSomething().then(() => 'Hello');
};
Say I have a function object-
setObj : function(a,b){
obj.a = a;
obj.b = b;
}
If I have to use async & await on this function object, how do I do it?
If the same was written in function (function way), say-
async function setObj(a,b){
obj.a = a;
obj.b = b;
}
await setObj(2,3);
This works fine. But, how do I do it in case of function object?
If I understand your question correctly, you can just use the async keyword in front of the method declaration:
let obj = {};
let myObj = {
async setObj(a,b) {
obj.a = a;
obj.b = b;
}
}
See http://tc39.github.io/ecmascript-asyncawait/#async-methods
UPDATE
You cannot use await outside of an async function. In order to use this you have to wrap that call to await setObj(2, 3):
async function consoleLog() {
await myObj.setObj(2, 3);
console.log(obj.a + obj.b);
}
consoleLog();
Use the same async keyword in your object's property:
(async function () {
var obj = {};
console.log("hello");
let setObj = async function (a,b){
obj.a = a;
obj.b = b;
};
await setObj(2,3);
console.log(obj.a+obj.b);
})();
Note that the entire code is wrapped in an asynchronous self-invoking function. This is needed, otherwise the await setObj will not be able to run correctly.
using arrow functions work as well
const myObject = {
myFunc: async () => {
await myResultHere
}
}
using this: Since the function is an async function, it will run asynchronously. If you want to run this with await, you will have to use it inside an async function
const useFunc = async () => {
const res = await myObject.myfunc();
}
You can simply put the async keyword on any function, not only function declarations but also function expressions and methods of object. For example:
As an method of an object:
const Object = {
async asyncFunction() {
await MyExamplepromise
}
}
As a variable:
const myFunc = async function () { await MyExamplepromise }
// this is how execute the function expression
// first () operator to execute, and use .then get access the resolved value
myFunc().then((val) => { console.log(val) })
Also notice that an async function returns a promise which will be resolved with the value returned by the async function, or rejected with an uncaught exception thrown from within the async function.