Difference betweeen Two line of same code - javascript

can someone explain to me the differenec between the two line of code. In my atom editor the prettier changes the first to second.
(await fetchSearchResults(state.requestConfig, context))?.facilities ?? [] )
and
await fetchSearchResults(state.requestConfig, context)?.facilities ?? [] )

The two lines are not the same and any automated change between these two is most likely incorrect.
To simplify, the difference is between:
(await foo()).bar
await foo() .bar:
Due to the operator precedence of await the second code (await foo().bar) will:
Execute foo()
Read the property bar from it
await that value
Which can be written as:
const functionResult = foo();
const result = await functionResult.bar;
While the first code uses the grouping operator () to change the order of operations to:
Execute foo()
await that value
Read the property bar from it
Which can be written as:
const functionResult = await foo();
const result = functionResult.bar;
This absolutely makes a difference if the function returns a promise:
function foo() {
return Promise.resolve({ bar: "hello world" });
}
async function main() {
console.log( await foo() .bar); // undefined - `foo()` returns a promise and there is no `bar` property
console.log((await foo()).bar); // "hello world" - since the promise resolves to { bar: "hello world" }
}
main();
It also makes a difference if foo() is synchronous but the bar property is a promise:
function foo() {
return { bar: Promise.resolve("hello world") };
}
async function main() {
console.log( await foo() .bar); // "hello world" since the promise resolves to that string
console.log((await foo()).bar); // Promise (check the browser console)
}
main();
The only time it does not make a difference is if there is no asynchronous code (which means the await probably should not be there):
function foo() {
return { bar: "hello world" };
}
async function main() {
console.log( await foo() .bar); // "hello world"
console.log((await foo()).bar); // "hello world"
}
main();

Prettier changes the whole thing to follow the rules given in a Prettier config file.
In your specific case, the (await fetchSearchResults(state.requestConfig, context)) is useless, hence why Prettier strips it.
Meanwhile, it may be quite important in a classic async context as explained in the comment below. Maybe the optional chaining is somehow tricking Prettier here, not sure.
The default Vue2 ESlint configuration comes with plugin:vue/essential and eslint:recommended as defaults.
Here is a link where you could get more details as of why.
If it's Prettier only, check the options part of the documenation or a .prettierrc config file in your project (or above).

You don't need those brackets as long as you are not going to use the promise result straight after as in the example below
(await fetchSearchResults(state.requestConfig, context))?.facilities ?? [] )?.someMethod()
but the line is already getting quite long so you are probably best assigning the promise result to a variable.

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);
}

await in for-of loop vs fetching the iterable before for-of

See the two code blocks below:
for await (const {key, value} of ctx.stub.getStateByRange(startKey, endKey)) {}
and
let allCarsRangeIterator = await ctx.stub.getStateByRange(startKey, endKey);
for (const {key, value} of allCarsRangeIterator ) {}
When I use the first one, everything works, but when I use the second one, I get an error saying allCarsRangeIterator is not iterable.
Why are these two not equivalent ?
I found this to be a very interesting question and dug around for a bit. Let's see if I can answer this properly:
First, we need to be clear about iterators and generators, so I encourage everyone to go through the linked documentation.
The following seems to be a generator:
ctx.stub.getStateByRange(startKey, endKey)
As per the docs, a generator is a special type of iterator that can be iterated over only once. On top of that, it seems to be a generator that does some async computation. Let's mock this with a simpler function:
async function* foo() {
yield 1;
yield new Promise((resolve) => setTimeout(resolve, 2000, 2));
yield 3;
}
As per the docs, in order for an object to be iterable, it needs to implement the Symbol.asyncIterator (async) or Symbol.iterator (sync) protocol. Let's check this:
async function* foo() {
yield 1;
yield new Promise((resolve) => setTimeout(resolve, 2000, 2));
yield 3;
}
(async function () {
const obj1 = foo();
console.log(typeof obj1[Symbol.iterator] === "function"); // false
console.log(typeof obj1[Symbol.asyncIterator] === "function"); // true
})();
Now let's see the output if we use await.
async function* foo() {
yield 1;
yield new Promise((resolve) => setTimeout(resolve, 2000, 2));
yield 3;
}
(async function () {
const obj1 = await foo();
console.log(typeof obj1[Symbol.iterator] === "function"); // false
console.log(typeof obj1[Symbol.asyncIterator] === "function"); // true
})();
It's still the same. This conforms to the error you got: allCarsRangeIterator is not iterable, because obj1 does not implement the Symbol.iterator protocol but rather the Symbol.asyncIterator protocol.
So, when you are trying to use for (const num of await foo()), it is a synchronous code, so it is going to look for Symbol.iterator protocol implementation. But since your function is an async generator, it only has Symbol.asyncIterator protocol implemented.
The only way to iterate over an async generator is therefore:
for await (const num of foo()) {
console.log(num);
}
You will also see that this is valid (although it looks weird)
for await (const num of await foo()) {
console.log(num);
}
Since (const num of await foo()) still has the Symbol.asyncIterator protocol implemented.
In fact, in VSCode, you will see a warning whenever you type for (const num of await foo()):
Type 'AsyncGenerator<any, void, unknown>' must have a '[Symbol.iterator]()' method that returns an iterator. ts(2488)
and const obj1 = await foo() shows the warning:
'await' has no effect on the type of this expression. ts(80007)
Additional resources:
for...await of
iterable and iterator protocols

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));

check type with instanof on an object that was casted

I have a function that returns an object of type Bar like this
myFunc() {
return <Bar>asyncGet(); / fetches the info and casts the server response to Bar
}
than in some controller, if I do
let bar = myFunc();
// bar instanceof Bar doesn't return true...
instanceof is not working as expected since I didn't instanciate bar via Bar constructor.
How can I check that the object returned by myFunc is of type Bar ?
Since your call to asyncGet is probably asynchronous - it is most likely returns Promise. Hence you need to either work with it oruse async/await approach. Something like this should watch:
myFunc() {
return <Bar>asyncGet();
}
myFunc().then(bar => { /* do something with it*/});
or
async myFunc() {
return <Bar>asyncGet();
}
let bar = await myFunc();
You can tell your function what type it has to return with :bar at the end.
Example:
myFunc():bar{
return <Bar>asyncGet(); / fetches the info and casts the server response to Bar
}
That way your function has to return of type bar.

Categories