Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the (potential) drawback of using async functions everywhere?

I am learning Javascript. This may sound like a crazy idea but I don't find clear answers on Google. Can I just replace all my regular functions/methods with async function everywhere? I mean there seems to be no downsides to this and it makes things so much simpler. Where the situation only involves synchronous steps, you just don't use await and it will work just like normal functions. Easy!

Personally I find having to distinguish async functions and normal functions unnecessarily burdensome. It's like driving a manual transmission car, where the car itself could easily handle the gearing by itself.

Am I missing something here?

like image 524
Jinghui Niu Avatar asked Jul 15 '18 09:07

Jinghui Niu


People also ask

What problem does async await solve?

Yes, async/await solves one problem in particular that generators alone cannot—the ability to await some asynchronous value from within a true generator (one yielding actual values, not a coroutine yielding promises or thunks into a trampoline).

Should I make every function async?

For the consumer - it is irrelevant if a function is async or just returns a promise. If you're writing an API and your function sometimes return promises it is best to make them always return promises - more generally if a function is sometimes asynchronous (with callbacks too) it should always be asynchronous.

What does async do to a function?

Async functions The word “async” before a function means one simple thing: a function always returns a promise. Other values are wrapped in a resolved promise automatically. So, async ensures that the function returns a promise, and wraps non-promises in it.

Are async functions non blocking?

@Martian2049: Yes; async is built on Promises, which are nonblocking. "It doesn't allow any new capabilities" It actually does. "So, async can't be used to "make something asynchronous" But await can.


1 Answers

async functions always return Promises. This means that anytime you're not dealing with something asynchronous, you would have to convert the returned Promise into a value before you could use it. For example:

const return4 = async () => 4;
console.log(4 + return4());

Instead, you would have to use the (unnecessarily wordy):

const return4 = async () => 4;
(async () => {
  console.log(4 + await return4());
})();

(or call .then on the return4 call before using it)

If return4 was not async, on the other hand, of course console.log(4 + return4()); alone would work just fine.

Another problem with async functions is that transpiling them to ES5 code (which allows for compatibility with obsolete browsers like IE) requires regenerator-runtime, which is very heavyweight. For example, transpiling the following single line with Babel:

const foo = async () => console.log('async!');

When you plug it into the repl, you get:

"use strict";

function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
  try {
    var info = gen[key](arg);
    var value = info.value;
  } catch (error) {
    reject(error);
    return;
  }
  if (info.done) {
    resolve(value);
  } else {
    Promise.resolve(value).then(_next, _throw);
  }
}

function _asyncToGenerator(fn) {
  return function() {
    var self = this,
      args = arguments;
    return new Promise(function(resolve, reject) {
      var gen = fn.apply(self, args);
      function _next(value) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
      }
      function _throw(err) {
        asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
      }
      _next(undefined);
    });
  };
}

var foo =
  /*#__PURE__*/
  (function() {
    var _ref = _asyncToGenerator(
      /*#__PURE__*/
      regeneratorRuntime.mark(function _callee() {
        return regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch ((_context.prev = _context.next)) {
              case 0:
                return _context.abrupt("return", console.log("async!"));

              case 1:
              case "end":
                return _context.stop();
            }
          }
        }, _callee);
      })
    );

    return function foo() {
      return _ref.apply(this, arguments);
    };
  })();

which also depends on regeneratorRuntime already being included in the script, which is 700-something lines of code that you can see here.

On less powerful systems, this can result in a not-insignificant performance hit. This is why some (such as with the AirBNB style guide) prefer to never use async functions, even if they make the asynchronous control flow of the script clearer.

like image 150
CertainPerformance Avatar answered Nov 03 '22 17:11

CertainPerformance