0

How could one create syntactical sugar to hide some of the complexity that is .then?

Given the code below:

const Fridge = {
  async openDoor() {
    const myCake = new Promise(resolve => {setTimeout(()=> {
      console.log('door opened')
      resolve (Object.create(Cake))
    }, 2000)});
    await myCake
    return myCake
  }
}

const Cake= {
  eatCake(){ console.log ( 'yummy now I can eat my cake' ) }
}

const myFridge = Object.create(Fridge)

Typically accessed via the verbatious:

myFridge.openDoor().then(myCake=>{
  myCake.eatCake()
  ... other code here .....
}) // complicated

Can some sugar be created to instead:

myFridge.openDoor().eatCake()  //simple to understand .then implied

or further, instead of:

myObject.myPromise.then(res=>{
   let x = res
   ... do stuff with x
});

rather

let x = myObject.myPromise.res
... so stuff with x

Whatever is returned from the async function should be used for the subsequent call. And all subsequent code is assumed to be in the .then. Closure of the .then is determined by the end of the enclosing function (similar to how the await currently works).

TrevTheDev
  • 2,616
  • 2
  • 18
  • 36

3 Answers3

2

You can use await preceding myFridge.openDoor() call wrapped in parenthesis to form an expression then chain .eatCake() to call the method of the object returned from .openDoor()

(async() => {
  (await myFridge.openDoor()).eatCake()
})()
guest271314
  • 1
  • 15
  • 104
  • 177
  • Thank you for the response I had thought of that but it is still a half solution, that would result in these still hard to read/create expressions: (await(await myFridge.openDoor()).eatCake()).getFat(). But better than .then though. – TrevTheDev Feb 03 '19 at 03:25
  • @TrevTheDev No, the code is not a _"half solution"_. The answer achieves the requirement described at the question. – guest271314 Feb 03 '19 at 03:26
  • how is (await(await myFridge.openDoor()).eatCake()).getFat() === myFridge.openDoor().eatCake().getFat() ? – TrevTheDev Feb 03 '19 at 03:29
  • @TrevTheDev What you describe hypothetically at the question and at the previous comment is not currently possible using JavaScript in practice. The code at the answer uses expressions to achieve essentially the same or similar pattern by using parentheses (an expression) for each `await` usage necessary to chain a method. – guest271314 Feb 03 '19 at 03:31
  • Ok, if it really is not possible, then the correct answer is not possible - although I doubt it is not possible - more likely just hard. In essence, the solution proposed is my question with a different format. – TrevTheDev Feb 03 '19 at 03:34
  • @TrevTheDev It is not possible until you show and prove otherwise. If in fact the pattern is possible but _"more likely just hard"_ then such a pattern would be contrary to the stated goal of the code in the first place. The pattern used at the answer uses only parentheses (two additional bytes per `await` usage) to achieve the expected result – guest271314 Feb 03 '19 at 03:36
  • One solution could be write a mini transpiler that translates said code to .then (so clearly not impossible). – TrevTheDev Feb 03 '19 at 03:38
  • @TrevTheDev So your solution is to write _more_ code at _"write a mini transpiler"_ than only two additional bytes per `await` operator usage, where the requirement is to write _less_ code? Again, until you show and prove otherwise it is not possible. – guest271314 Feb 03 '19 at 03:39
  • It is a better solution than the one proposed - because it makes the consumer exposed interface MUCH cleaner and simpler. – TrevTheDev Feb 03 '19 at 03:40
  • @TrevTheDev Then write the code and show and prove https://stackoverflow.com/help/self-answer. Though that is still contrary to the stated requirement at the question to write _less_ code to achieve the expected result, you can prove your hypothesis nonetheless. – guest271314 Feb 03 '19 at 03:41
  • Are you suggesting myFridge.openDoor().eatCake() cannot be transpiled to myFridge.openDoor().then(myCake=>{myCake.eatCake()}) ? – TrevTheDev Feb 03 '19 at 03:43
  • @TrevTheDev Not following. The requirement is to not use `.then()` and to use the least amount of code as possible, correct? Yes, you can create a `Promise` method which returns a `new Promise` and uses `.then()` within the method [Delay chained promise](https://stackoverflow.com/a/38734306/), though that is an abstraction which still uses more code (more bytes than the solution at the present answer). – guest271314 Feb 03 '19 at 03:44
  • The goal is to create syntactical sugar that abstracts away the complexity of await and .then - The solution will require more code, but the interface will be better. – TrevTheDev Feb 03 '19 at 03:46
  • @TrevTheDev "better" is entirely subjective. This is the actual question: _"How could one create syntactical sugar to hide some of the complexity that is .then?"_ and _"Can some sugar be created to instead: `myFridge.openDoor().eatCake()`"_ which the code at the answer achieves using an expression. If the question means something other than the language and code used at the current question kindly update the question to precisely describe what the requirement is. – guest271314 Feb 03 '19 at 03:48
  • The question included: Can some sugar be created to myFridge.openDoor().eatCake() which this solution does not achieve. – TrevTheDev Feb 03 '19 at 03:52
  • @TrevTheDev Have you read the link at the previous comment? That pattern is possible already, though requires defining additional methods and more code. If the goal is to use less code, then you can use the pattern at the answer. Or, again, post an answer to your own question. – guest271314 Feb 03 '19 at 03:53
  • 1
    Thank you @guest271314, your idea re the prototyping led me down a rabbit hole which led me to proxy's and then after much pain, the solution posted! – TrevTheDev Feb 05 '19 at 07:03
  • @TrevTheDev At least you traveled along the rabbit proof fence trying to get home and found out for yourself. – guest271314 Feb 05 '19 at 07:11
0

there is a syntax called try()catch() in Combine with async await

example:

async function someAsyncFunction () {
   try {
      const asyncValue = await asyncCall() //Promise
      console.log(asyncValue) // this will log only when asyncCall resolved
    }catch(error) {
     throw error
   }
  }

instead of using Promise and chain a then() with a callback to it.

you do await asyncCall() and under that you can keep writing more code with the resolved value instead of chaining more functions with callbacks

Its hard to explain and understand on 1 foot so here is some resource for async await

elad BA
  • 1,760
  • 11
  • 17
0

Here is a solution that provides syntactical sugar that can be used to hide the complexities of await and .then:

const promiseNodeH = {
  get(target, prop) {
    if (prop in target || typeof prop !== 'string') return target[prop]
    return function() {
      const x = arguments
      const p3 = new Promise(resolve => {
        target.then(value => {
          resolve(value[prop](...x))
        })
      })
      return new Proxy(p3, Object.create(promiseNodeH))
    }
  }
}

const Cake = {
  eatCake(msg) {
    console.log(`starting to eat cake: ${msg}!`)
    const self = this
    return new Promise(resolve => {
      setTimeout(function() {
        console.log('cake eaten')
        resolve(self)
      }, 5000)
    })
  },
  getFat() {
    console.log('burp')
  }
}

const Fridge = {
  openDoor() {
    console.log('start to open door')
    const p1 = new Promise(resolve => {
      setTimeout(function() {
        console.log('door is open, here is your cake')
        resolve(Object.create(Cake))
      }, 5000)
    })
    return new Proxy(p1, Object.create(promiseNodeH))
  }
}

Can be accessed via:

Fridge.openDoor().eatCake('Yummy').getFat()
TrevTheDev
  • 2,616
  • 2
  • 18
  • 36
  • _"Here is a solution that avoids await and .then:"_ Except the pattern does not avoid `.then()` `target.then(value => { resolve(value[prop](...x)) })` – guest271314 Feb 05 '19 at 07:09
  • @guest271314 does from an interface perspective: It allows one to expose an api to downstream users that is not littered with .then and await. Users only have to type Fridge.openDoor().eatCake('Yummy').getFat() - .then and await not required. – TrevTheDev Feb 05 '19 at 07:11
  • The text at the beginning of the answer which describes the pattern is not true and correct. The code does in fact not avoid using `.then()`. – guest271314 Feb 05 '19 at 07:12
  • @guest271314 updated to better reflect your comment. – TrevTheDev Feb 05 '19 at 07:17
  • If that is your perspective so be it. There is nothing hidden. The code is an abstraction that still uses `.then()`. – guest271314 Feb 05 '19 at 07:18
  • @guest271314 it is much better to provide an api as shown to users, vs. requiring them to understand which calls are async and handle them with await and .then. In fact this likely should be the default treatment of promises in Javascript as it is intuitive. – TrevTheDev Feb 05 '19 at 07:21
  • That is perhaps taking your own interpretation of the pattern at the answer too far. Again, the code is only an abstraction. When changes need to be made or an error or bug occurs the entire code will need to be evaluated, removing the veil of the abstraction. – guest271314 Feb 05 '19 at 07:25
  • @guest271314 if one makes an async call _.then_ is only useful if the rest of ones code is written in an async manner with _promises_ and _.then's_ everywhere. In my solution the **.** becomes analogous to _AWAIT_ which is touted as making async code clearer and easier to read. It does not prevent the aforementioned complexity, but does provide a default optional simpler solution. Whilst make code simpler, the downside is that this code becomes synchronous by default, which may not be okay. This is the same thing that happens with AWAIT – which also halts execution before proceeding. – TrevTheDev Feb 05 '19 at 07:51
  • 1
    If you have convinced yourself that the abstraction meets the requirement of the question, so be it. That does not mean that you can convince everyone that what you consider "complexity" is somehow hidden. _"complexity"_ is subjective. The code is not hidden. The code at the answer could be considered to have more "complexity" than simply using `.then()` and `await` once an individual unwraps the abstraction (reads the source code). In any event it is your question and you have answered your own question, evidently to your own satisfaction, which is what matters because it is your question. – guest271314 Feb 05 '19 at 07:59
  • 1
    @guest271314 lol, I was hoping to convince you of the brilliance of my argument - oh well I'll have to be satisfied with my infallible self-belief ;). Thanks again for your challenge, it helped find this solution. – TrevTheDev Feb 05 '19 at 08:29