# Turning functions with a callback async

**URL:** <https://es.discourse.group/t/turning-functions-with-a-callback-async/696>\
**Category:** 💡 Ideas\
**Created:** [March 15, 2021, 7:25pm UTC](https://es.discourse.group/t/turning-functions-with-a-callback-async/696 "2021-03-15T19:25:38Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![vrugtehagel](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/vrugtehagel/32/653_2.png) [@vrugtehagel](https://es.discourse.group/u/vrugtehagel)\
**Post date:** [March 15, 2021, 7:25pm UTC](https://es.discourse.group/t/turning-functions-with-a-callback-async/696/1 "2021-03-15T19:25:38Z")

</div>

Recently, I was looking into some browser extension API's and noticed that it's very heavy on callbacks. It became apparent that people were aware of this, since in a newer version, they've made many of the methods provided async. Essentially transforming methods from

```javascript
some.api.method(foo, bar, result => {
    // do something
});

```

to

```javascript
await result = some.api.method(foo, bar);
// do something

```

This is nice because it keeps things simple and readable, and things don't become a pyramid of indentation.

I realized this pattern is not just applicable to extension API's, but to any function with a callback. This gave me an idea; what if we had some syntax to create this without the need for the method itself to be async?

For example, instead of this

```javascript
function asyncAPIMethod(foo, bar){
    return new Promise(resolve => some.api.method(foo, bar, resolve));
}

```

what if we could just write this:

```javascript
await some.api.method(foo, bar, %resolve);

```

(okay, maybe not write `%resolve`, but this is just a demonstration of the idea).  
This would open up quite some doors:

```javascript
// wait until the document loads
await document.addEventListener('DOMContentLoaded', %resolve);
// wait 1 second
await setTimeout(%resolve, 1000);
// wait until my favorite image loads
await image.addEventListener('load', %resolve);

```

This would also mean we don't have to force an async API onto users, but users get to choose for themselves whether they want to `await` our callback or if they want things to be synchronous.

Thoughts?

---

<div class="post-metadata">

**Author:** ![bakkot](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/bakkot/32/22_2.png) [@bakkot](https://es.discourse.group/u/bakkot)\
**Post date:** [March 15, 2021, 9:34pm UTC](https://es.discourse.group/t/turning-functions-with-a-callback-async/696/2 "2021-03-15T21:34:48Z")

</div>

You can already do `await new Promise(resolve => some.api.method(foo, bar, resolve))`. That seems simple and clear to me, such that it doesn't really make sense to try to add new syntax to address this use case. Do you disagree?

---

<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 16, 2021, 2:32am UTC](https://es.discourse.group/t/turning-functions-with-a-callback-async/696/3 "2021-03-16T02:32:04Z")

</div>

It also gets tricky if you're dealing with node-style callbacks, where the error is passed in as the first argument. There wouldn't be an easy way to translate those into promise rejections.

It seems like a nice idea, but it also seems hard to make it flexible enough to handle different callback styles.

---

<div class="post-metadata">

**Author:** ![vrugtehagel](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/vrugtehagel/32/653_2.png) [@vrugtehagel](https://es.discourse.group/u/vrugtehagel)\
**Post date:** [March 16, 2021, 6:46am UTC](https://es.discourse.group/t/turning-functions-with-a-callback-async/696/4 "2021-03-16T06:46:07Z")

</div>

@bakkot I disagree somewhat - yes, I can wrap it in a promise just fine, but that's a bit verbose and generally needs to be its own separate function. On the other hand, you may be right in that the use case is not broad enough to justify this idea.

@theScottyJam well, we could potentially return the aruments as an array, so one could do

```javascript
const [error, data] = await fetchData(%resolve);

```

this would however make single-argument callbacks uglier because you'd expect it to return a single value, not an array of a single value.

---

<div class="post-metadata">

**Author:** ![Clemdz](https://yyz2.discourse-cdn.com/free1/user_avatar/es.discourse.group/clemdz/32/813_2.png) [@Clemdz](https://es.discourse.group/u/Clemdz)\
**Post date:** [March 16, 2021, 9:30am UTC](https://es.discourse.group/t/turning-functions-with-a-callback-async/696/5 "2021-03-16T09:30:24Z")

</div>

I'm not sure it worth adding a new syntax, we can already promisify callbacks using wrapper functions, and the result looks not that bad:

```javascript
const promisify = function (funct) {
  return (...args) => new Promise((res) => funct(...args, res));
}

// Using it
const res = await promisify(some.api.method)(foo, bar);

```

For Node callbacks, we can create a variation:

```javascript
promisify.node = function (funct) {
  return (...args) => new Promise((res, rej) => funct(...args, (err, data) => {
    if (err) rej();
    res(data);
  }));
}

// Using it
try {
  const res = await promisify.node(some.node.api.method)(foo, bar);
} catch (err) {
  console.error(err);
}

```

There is also the `util.promisify` function of Node achieving something similar for Node callbacks.

---

<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 16, 2021, 9:31am UTC](https://es.discourse.group/t/turning-functions-with-a-callback-async/696/6 "2021-03-16T09:31:19Z")

</div>

A related (stage 1, may not happen, can change) idea is [GitHub - tc39/proposal-partial-application: Proposal to add partial application to ECMAScript](https://github.com/tc39/proposal-partial-application)

Which for the examples in this thread could look something like:

```javascript
// generic helper
const P = fn => new Promise(fn)

const v = await P(document.addEventListener('DOMContentLoaded', ?))

```
