# Await postfix operator(@)

**URL:** <https://es.discourse.group/t/await-postfix-operator/1244>\
**Category:** 💡 Ideas\
**Created:** [March 9, 2022, 8:36am UTC](https://es.discourse.group/t/await-postfix-operator/1244 "2022-03-09T08:36:57Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![tzengshinfu](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/tzengshinfu/32/1260_2.png) [@tzengshinfu](https://es.discourse.group/u/tzengshinfu)\
**Post date:** [March 9, 2022, 8:36am UTC](https://es.discourse.group/t/await-postfix-operator/1244/1 "2022-03-09T08:36:58Z")

</div>

## **Summary**

Add " **@**" as await postfix opoerator("at sign" means "await") to let code looks more like synchronous.

" **@**" works like below:

```javascript
asyncFunction()@

```

it's equivalent to

```javascript
(await asyncFunction())

```

## **Use cases**

1. Take a look at this example. (from [Google/zx](https://github.com/google/zx))

- With " **@**" before

```javascript
#!/usr/bin/env zx

await $`cat package.json | grep name`

let branch = await $`git branch --show-current`
await $`dep deploy --branch=${branch}`

await Promise.all([
  $`sleep 1; echo 1`,
  $`sleep 2; echo 2`,
  $`sleep 3; echo 3`,
])

let name = 'foo bar'
await $`mkdir /tmp/${name}`

```

- With " **@**" after

```javascript
#!/usr/bin/env zx

$`cat package.json | grep name`@ //await here

let branch = $`git branch --show-current`@ //await here
$`dep deploy --branch=${branch}`@ //await here

Promise.all([
  $`sleep 1; echo 1`,
  $`sleep 2; echo 2`,
  $`sleep 3; echo 3`,
])@ //await here

let name = 'foo bar'
$`mkdir /tmp/${name}`@ //await here

```

1. Get the result of a promise without parenthesis.

- With " **@**" before

```javascript
let asyncCalculateResult = (await asyncCalculator.plusAsync(100)).calculateResult

```

- With " **@**" after

```javascript
let asyncCalculateResult = asyncCalculator.plusAsync(100)@.calculateResult

```

1. Simplify asynchronous for...of syntax.

- With " **@**" before

```javascript
for await (let number of getAsyncSequenceNumbers(10)) {
    //do something
}

```

- With " **@**" after

```javascript
for (let number of getAsyncSequenceNumbers(10)@) {
  //do something
}

```

## **Why choose "@"?**

### To protect our eyes

I found there is other languages choose await postfix keyword.

- Kotlin  
With "**.await()**"

- Rust  
With " **.await**"

Take a look at this asynchronous method chaining.

```javascript
await (await (await (await asyncCalculator.plusAsync(1)).minusAsync(2)).multiplyAsync(3)).divideAsync(4);

```

- With "**.await()**"

```kotlin
asyncCalculator.plusAsync(1).await() .minusAsync(2).await() .multiplyAsync(3).await() .divideAsync(4).await() .calculateResult

```

- With " **@**" 

```
asyncCalculator.plusAsync(1)@ .minusAsync(2)@ .multiplyAsync(3)@ .divideAsync(4)@ .calculateResult

```

`
`
`
`

``

It is difficult to read when too much characters in the method chaining,  
" **@**" can split them and be highlighted by code editor to group the asynchronous functions.

## **Other benefit**

### To protect our fingers and keyboard

- With " **@**" before

- With " **@**" after

## **How to try it out**

If you have VS Code, you can install this [demo extension](https://marketplace.visualstudio.com/items?itemName=tzengshinfu.demo-await-postfix-operator) to try it out.

## **About this idea**

It is inspired by the discussion of [async deference operator](https://github.com/dotnet/csharplang/discussions/1117).

---

<div class="post-metadata">

**Author:** ![aclaymore](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/aclaymore/32/501_2.png) [@aclaymore](https://es.discourse.group/u/aclaymore)\
**Post date:** [March 9, 2022, 10:34am UTC](https://es.discourse.group/t/await-postfix-operator/1244/2 "2022-03-09T10:34:11Z")

</div>

> [@tzengshinfu](#):
>
> - With " **@**"
> 
> ```javascript
> asyncCalculator.plusAsync(1)@ .minusAsync(2)@ .multiplyAsync(3)@ .divideAsync(4)@ .calculateResult
> 
> ```
> 
> It is difficult to read when too much characters in the method chaining,

Some related ideas here if you haven't seen before:

> **[GitHub - tc39/proposal-wavy-dot: TC39 Wavy Dot ("~.") Proposal](https://github.com/tc39/proposal-wavy-dot)**
>
> TC39 Wavy Dot ("~.") Proposal. Contribute to tc39/proposal-wavy-dot development by creating an account on GitHub.

Where it would look like:

```javascript
let result = await asyncCalculator.plusAsync(1)~.minusAsync(2)~.multiplyAsync(3)~.divideAsync(4)~.calculateResult;

```

---

<div class="post-metadata">

**Author:** ![mhofman](https://avatars.discourse-cdn.com/v4/letter/m/f14d63/32.png) [@mhofman](https://es.discourse.group/u/mhofman)\
**Post date:** [March 9, 2022, 2:43pm UTC](https://es.discourse.group/t/await-postfix-operator/1244/3 "2022-03-09T14:43:20Z")

</div>

I actually like the weight of the `await` keyword, and it's position as a prefix, as it represents an interleaving/suspension point that shouldn't be glossed over.

The nesting readability concern is greatly reduced with [pipelines](https://github.com/tc39/proposal-pipeline-operator), and `await` is one of the motivating use cases (and one of the reason why hack pipes were favored).

The wavy dot proposal is actually a lot more complex than simply awaiting on intermediate results as it allows pipelining. It's likely that a combination of pipeline and runtime helpers would sufficiently reduce the need for wavy dot, which is a reason why we haven't pushed it further for now.

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [March 9, 2022, 2:46pm UTC](https://es.discourse.group/t/await-postfix-operator/1244/4 "2022-03-09T14:46:30Z")

</div>

@aclaymore's referenced proposal would directly solve this issue, and it would be nice to see something like that added. As for what can be done today, I've started making it a habit to just use `.then()` instead of parentheses whenever I need to nest awaits. It generally makes the result a little cleaner.

Some examples:

```javascript
// before
await (await fetch('https://example.com')).text()

// after
await fetch('https://example.com').then(x => x.text())

// before
await (await (await (await asyncCalculator.plusAsync(1)).minusAsync(2)).multiplyAsync(3)).divideAsync(4);

// after
await asyncCalculator.plusAsync(1)
  .then(x => x.minusAsync(2))
  .then(x => x.multiplyAsync(3))
  .then(x => x.divideAsync(4))

```

Also, for this point:

> To protect our fingers and keyboard

In general, it's better to optimize for readability over writability, as code is read much more often than it is written. So, while this argument is still a valid one, it's generally put really low on the list of priorities. It's often overshadowed by things like: how readable is this new operator over the old one? (which, I'd argue if we're not nesting, the `await` operator is more readable, but that's really a matter of taste). Do we really need to use one of our few precious ascii symbols for this? If we introduce too many operators like this, will JavaScript just turn into an ascii soup that's difficult to understand? etc.

**Edit:** Just saw @mhofman's comment. Nested awaits have always been a bit of a pain point for me. When I started using the `.then()` trick, it helped out a lot. I didn't think about how pipelines would fix this, but yeah, I guess that would help fix the issue a lot - to the point where I wouldn't really feel a desire for this sort of feature anymore. But, I guess pipelines aren't that much different from just using `.then()` as well, which might be why I found that to be so helpful.

---

<div class="post-metadata">

**Author:** ![tzengshinfu](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/tzengshinfu/32/1260_2.png) [@tzengshinfu](https://es.discourse.group/u/tzengshinfu)\
**Post date:** [March 10, 2022, 6:27am UTC](https://es.discourse.group/t/await-postfix-operator/1244/5 "2022-03-10T06:27:55Z")

</div>

Hi, @aclaymore ,  
Thank you for your information!

"~" looks like the liquid in pipeline flows to another side, it's nice.

---

<div class="post-metadata">

**Author:** ![tzengshinfu](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/tzengshinfu/32/1260_2.png) [@tzengshinfu](https://es.discourse.group/u/tzengshinfu)\
**Post date:** [March 10, 2022, 6:41am UTC](https://es.discourse.group/t/await-postfix-operator/1244/6 "2022-03-10T06:41:44Z")

</div>

Hi, @mhofman ,  
Thank you for your opinion!

The pipeline operator "|\>" looks more intuitive thant "~", it's great.

---

<div class="post-metadata">

**Author:** ![tzengshinfu](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/tzengshinfu/32/1260_2.png) [@tzengshinfu](https://es.discourse.group/u/tzengshinfu)\
**Post date:** [March 10, 2022, 6:53am UTC](https://es.discourse.group/t/await-postfix-operator/1244/7 "2022-03-10T06:53:39Z")

</div>

Hi, @theScottyJam ,  
Thank you for your sharing.  
That's awesome!  
It looks simple, easy to understand and useful.  
I really learned from your example.

---

<div class="post-metadata">

**Author:** ![tzengshinfu](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/tzengshinfu/32/1260_2.png) [@tzengshinfu](https://es.discourse.group/u/tzengshinfu)\
**Post date:** [March 23, 2022, 11:49am UTC](https://es.discourse.group/t/await-postfix-operator/1244/8 "2022-03-23T11:49:56Z")

</div>

Chaining method calls is so easy to use,  
so I created a tiny library to convert synchronous nested method calls to chaining method calls.

> **[synchronous-then](https://www.npmjs.com/package/synchronous-then)**
>
> Convert nested method calls to chaining method calls without class or wrapper functions.. Latest version: 0.0.1, last published: an hour ago. Start using synchronous-then in your project by running \`npm i synchronous-then\`. There are no other...

---

<div class="post-metadata">

**Author:** ![theScottyJam](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/thescottyjam/32/616_2.png) [@theScottyJam](https://es.discourse.group/u/theScottyJam)\
**Post date:** [March 23, 2022, 1:55pm UTC](https://es.discourse.group/t/await-postfix-operator/1244/9 "2022-03-23T13:55:48Z")

</div>

@tzengshinfu - careful there. It's generally recommended not to modify the prototypes of built-in objects, and that's done for good reason - you might add a function that conflicts with current or future JavaScript functions, or that conflicts with other libraries. (Every time JavaScript tries to add a function, they generally have to look around to make sure their function doesn't cause issues with any libraries that have modified built-in prototypes.

In this case, your library actually conflicts with an existing protocol - the "thenable" protocol. Promises will chain with anything that has a `then` function

This means:

```javascript
> Date.prototype.then = () => console.log('hi there')
> await Promise.resolve().then(() => new Date())
hi there
(script never terminates)

```

Or, if I run this line of code after loading your library in, the promise will never resolve and the script will never terminate.

```javascript
> console.log(await Promise.resolve().then(() => new Date()))
(script never terminates)

```

Part of the issue here is the fact that that ES6 chose to make anything with a then() function implement this protocol (as opposed to using symbols), which can cause surprising effects to anyone who adds a "then()" function to their objects. But, the fact that you're modifying prototypes means existing code that tries to return a Date object or what-not from a promise will break, which makes things even worse.

You could just fix this by renaming the function, but my personal recommendation would be to do something that you might not like, because it's a bit more verbose. (This is how [lodash](https://lodash.com/docs/4.17.15#chain) solves the problem).

```javascript
import chain from 'your-library'

return chain(2 + 2) // Returns an object that holds the internal value, and has a .then() function
  .then(x => x + 1) // Or call it next() or something if you want this to not be then-able.
  .then(x => x * 2)
  .value() // Gets the internal value out of this wrapper object

```

---

<div class="post-metadata">

**Author:** ![tzengshinfu](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/tzengshinfu/32/1260_2.png) [@tzengshinfu](https://es.discourse.group/u/tzengshinfu)\
**Post date:** [March 25, 2022, 4:46am UTC](https://es.discourse.group/t/await-postfix-operator/1244/10 "2022-03-25T04:46:22Z")

</div>

Hi, @theScottyJam ,  
Thank you for your explaining, I learned a lot from you again.

Now I got it, Thenable protocol, Duck typing, and don't pollute the prototypes of built-in objects.  
I will build a wrapper object to chain it's mehods.
