Losing object reference in Javascript with await - javascript

I was learning the event loop of Js and tried to run this function:
async function foo() {
console.log('FIrst');
let a = await new Promise((resolve,reject)=>{
console.log("inside Promise");
resolve();
})
console.log(a);
console.log('Second');
}
foo();
console.log('Three');
On running this code gave output as follows:
FIrst
inside Promise
Three
undefined
Second
I am not able to understand why did a lose its value (the object assignment). I have searched for this behavior but was not able to understand from the answers.
Can someone please explain what is the order of execution which results in this output.

When you await the newly created promise, you're not assigning the promise to a, you're assigning the resolve value of it.
async function foo() {
let a = await new Promise((resolve, reject) => {
// This is where the value stems from
resolve(42);
});
console.log(a);
}
foo();
If you want to keep the await while also retrieving the reference, you can separate those two steps:
async function foo() {
let a = new Promise((resolve, reject) => {
resolve(42);
});
await a;
console.log(a instanceof Promise);
}
foo();

This is because if you are using await it returns to a variable the thing that you've passed in resolve, so you didn't pass any value in resole this is why it is undefined

The reason why the promise's value is undefined is because you did not set the value that the promise should output. If you want the promise to return something other than undefined, place an expression or string inside the resolve() function. If you want the promise to return "Promise completed" after it resolves and console.log the result, simply use the code
async function foo() {
let a = await new Promise((resolve,reject)=>{
resolve("Promise completed");
})
console.log(a);
}
foo();

Related

How to call an async function inside an if statement?

To keep variables in background.js in chrome extension I need to reinitiate some global variables, and I meet some difficulties.
Here is the code(fiddle) that I want to use to illustrate the problem:
var temp = null;
function someTimeConsumingThing() {
return new Promise(function(resolve,reject) {
setTimeout(resolve, 2000);
temp = 10;
})
}
async function a(){
if(temp==null){
await someTimeConsumingThing();
}
return temp
}
function b(){
let localTemp = a();
console.log(localTemp);
}
b();
In the above code snippet, the temp variable would sometimes be null and to ensure that temp is not null I should call an async function someTimeConsumingThing. As we can see, the console.log outputs a Promise rather than 10; and an error would occur if I add await before a():
Uncaught SyntaxError: await is only valid in async functions and the top level bodies of modules"
How can I tackle this problem? I have read many related but unhelpful answers here and I don't know how to optimize my search input to get the most related question. This problem would be very naive for JS experts and there are certainly available answers on this site.
You forgot to use await when calling a(), which means you printed the returned promise instead of the async result of a(). The containing function therefore also needs to be async, since it contains an await call.
Note that it's good practice to mark the someTimeConsumingThing function as async, because it returns a Promise.
Also note that your someTimeConsumingThing function sets temp to 10 immediately, and then delays until returning. I've rewritten it so it only sets temp to 10 after the delay has completed.
let temp = null;
async function someTimeConsumingThing() {
return new Promise(resolve => {
setTimeout(()=>{
temp = 10;
resolve();
}, 2000);
})
}
async function a(){
if(temp==null){
await someTimeConsumingThing();
}
return temp;
}
async function b(){
let localTemp = await a();
console.log(localTemp);
}
b();
A function that calls an async function and needs the result of that function, must in itself (by definition) be asynchronous.
Just change b so that it is an async function:
async function b(){
let localTemp = await a();
console.log(localTemp);
}

typescript await in getter [duplicate]

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`
}

await with overloaded methods

I have an ES6 class hierarchy. All of the classes in the hierarchy implement a draw() method. Some implement it synchronously but some need this method to be async.
How can I call draw() correctly in this sort of setup?
Is it possible to find if the method being called is async and only then call await on it's result?
You could check if the draw() has a .then function since all promises will have to implement that. If it does, use async, else execute directly
Check this answer on how to determine a promise How do I tell if an object is a Promise?
if(draw.then) { // all async await functions wrap the return into promises. So, this should
const resolvedData = await draw(); // store the data if you need to get the value
else
draw()
I wanted to avoid having to decla(r)e 100 methods as async for the
sake of just the two that actually need it.
A function doesn't have to be async (ie: return a promise) to be awaited. A synchronous function can be awaited too. This means that if a promise is not returned by draw() (ie: your draw() method is synchronous), then the await will convert the returned value of draw() to a resolved promise which it then waits for and retrieves its value.
So, something like the following is possible:
function foo() { // returns a string
return "foo";
}
async function bar() { // implicitly returns a promise
return "bar";
}
(async function() {
const fooStr = await foo(); // foo() is synchronous, but can be `await`ed still
const barStr = await bar(); // bar() is asynchronous, and can be `await`ed
console.log(fooStr, barStr);
})();
With this in mind, you don't need to know if draw() is synchronous or not, instead, you can always await the draw() method, regardless of its return type.
You can check your function if it is async function by using Object.prototype.constructor.name.
var object = {
draw: async function() {}
}
var object1 = {
draw: function() {}
}
console.log(object.draw.constructor.name);
console.log(object1.draw.constructor.name);

Does the asyc\await syntax resolve chained functions?

In this example, if the function was run, would both promises get resolved before foo is return ?
async function() {
var foo = await iReturnAPromise().iReturnAPromiseUnrelatedToMyParent();
return foo;
}
foo as it is, can only carry one resolution. You may do like
foo = await iReturnAPromise().then(v => (doSomeThingWith(v), iReturnAPromiseUnrelatedToMyParent()));
in which case foo will be assigned the resolution of iReturnAPromiseUnrelatedToMyParent. However if you would like to access both resolutions (which are independent of each other) then you may do like;
async function test(){
[foo,bar] = await Promise.all([Promise.resolve(10), Promise.resolve(20)]);
return [foo,bar];
}
test().then(([a,b]) => console.log(a,b));

Understanding of Promises

I want to implement deferred with native Promise and made some experiments.
var p, _p;
p = new Promise((t, f) => {
p.resolve = t;
p.reject = f;
_p = p; // let's save it into global
});
p.then(
console.log.bind(console, 'ok'),
console.log.bind(console, 'fail')
);
console.log(p === _p); // false!
console.log(typeof p.resolve, typeof _p.resolve); // 'undefined' 'function'
_p.resolve(42); // 'ok' 42
What p was pointed inside the promise function?
Why it is some another instance? How can I extend returned one?
What p was pointed inside the promise function?
When you're setting your p in promise, you're referencing to a global p (the one you declared).
var p, _p; // declared, but not value set
p = new Promise((t, f) => {
console.log(p); //undefined
console.log(window.hasOwnProperty("p")); //true
window.p = 3;
console.log(p); // 3
});
console.log(p); // promise
As you haven't set any value for your p before promise call, it's value is undefined.
Why it is some another instance? How can I extend returned one?
Because in the time when you're setting properties on p, your call to promise hasn't finished yet. Browser has first executes arguments you are sending to promise (that is your arrow function) , then calls your promise with arguments and only after that it assigns return value of promise to variable p (and overwrites any changes you made to p inside your arrow function).
The only way to extend the returned Promise object is to extend it after it has been created and assigned to your p
Thanks guys for point my fault.
I ended up with followed implementation:
function Deferred() {
this.promise = new Promise((ok, fail) => {
this.resolve = ok;
this.reject = fail;
});
}
!function() {
var p = new Deferred();
p.promise.then(
console.log.bind(console, 'ok'),
console.log.bind(console, 'fail')
);
p.resolve(42); // ok 42
}();
Extending of Promise object was a bad idea.
p does get reject and resolve functions appended to it when you define them:
p = new Promise((t, f) => {
console.log(p) // it is not defined as a promise
p.resolve = t;
p.reject = f;
console.log(p) // p now is defined AND has resolve and reject defined in it
_p = p // _p now is a promise object with resolve and reject defined
});
However, the moment you finish creating your promise, it will lose all the extra elements you've added to it. If you want to extend your p for whatever reason, you can do it after the promise has been created. For instance
p = new Promise((t, f) => {
console.log(p) // it is already defined as a promise
p.resolve = t;
p.reject = f;
console.log(p) // p now has resolve and reject defined in it too
_p = p // _p now is a promise object with resolve and reject defined
});
p.extraExtension = "hello"
console.log(p); // at this stage your p will have extraExtension extended to it, but its attributes and status as a Promise are also there. However, simply defining `p.resolve` and `p.reject` wouldn't make them function as proper resolve and reject methods for the promise.
Promises already have resolve and reject defined in them:
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject
The way to call them is to simply refer to them inside the promise object:
p = new Promise((t, f) => {
console.log(p) // it is already defined as a promise
resolve(t); // the promise will now resolve. Similarly you can call reject() here.
});
For more information refer to the official documentation here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
You can see all the inherent methods and properties of a Promise object there.

Categories