Pull to refresh

Comments 12

Для TypeScript полезно правило линтера promise-function-async. Инстинктивно стараюсь избегать вызова асинхронных функций из синхронных, в идеале then/catch остаются только в единственной точке входа.

Надо просто понимать, во что развернётся сахар async'а.
Перепишите вашу функцию так:
function fn(obj) {
  return new Promise((resolve, reject) => {
    try {
      const someProp = obj.someProp;
      resolve(someProp);
    } catch (e) {
      reject(e);
    }
  })
}

Это как раз пример того как делать НЕ надо. Во-первых, конструктор Promise сам поймает ошибку, try-catch тут полностью лишний. Ну или же лишним можно считать new Promise, поскольку try-catch тут и сам справится.


Во-вторых, написать async гораздо проще.

Он во что-то такое развернётся:


function fn(obj) {
  return new Promise( resolve => {
    const someProp = obj.someProp;
    resolve(someProp);
  } )
}

Перевод, это конечно круто. Но перевод ради перевода? Если хотели сделать полезное, то перевели бы и единственный комментарий к оригиналу, объясняющий, почему автор неправ.

Иногда встречаются рекомендации начинать цепочку промисов с Promise.resolve() — как раз чтобы избежать описанной проблемы.
То есть вместо


userModel.getUserById(req.params.id)
    .then(user => res.json(user))
    .catch()

пишем


Promise.resolve()
    .then(() => userModel.getUserById(req.params.id))
    .then(user => res.json(user))
    .catch()

Минус — лишний код. Плюс — работает даже в случае, когда userModel.getUserById пришла из сторонней библиотеки, и мы не можем явно пометить ее как async

Выше уже заметили, что нужно помещать код внутрь new Promise((resolve, reject) => {...}), чтобы избежать такой проблемы (в случае если async-await по какой-то причине использовать нельзя, например, IE11).


В общем-то именно ради возможности словить ошибку и появилось такое API c замыканием вместо классического Defferred.resolve/reject из jQuery и других ранних реализаций промисов. Вот тут можно почитать подробнее: https://stackoverflow.com/questions/28687566/difference-between-defer-promise-and-promise

в случае если async-await по какой-то причине использовать нельзя, например, IE11

ну в IE11 и Promise нативно не поддерживается, так что реальных причин не использовать везде async-await не существует.

Полифилл promise подключается один раз и весит 1Kb или около того, а транспиляция раздувает исходный код. Было


async function loadJSON() {
  const response = await fetch('/url');
  const json = await response.json();
  return json;
}

стало


function loadJSON() {
  var response, json;
  return regeneratorRuntime.async(function loadJSON$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          _context.next = 2;
          return regeneratorRuntime.awrap(fetch('/url'));

        case 2:
          response = _context.sent;
          _context.next = 5;
          return regeneratorRuntime.awrap(response.json());

        case 5:
          json = _context.sent;
          return _context.abrupt("return", json);

        case 7:
        case "end":
          return _context.stop();
      }
    }
  });
}

Поэтому я могу вполне себе представить вариант, где Promise доступен, а async/await – нет.

Не могу утверждть, работает ли это так как ожидается, но есть плагин для babel, который преобразует async-await в Promise.
Т.е. решая проблему "в лоб" можно глобально подключить полифил + плагин для async->Promise

Интересно, хороший плагин, очень жаль, что стандартный @babel/preset-env, производит намного больше кода.

Судя по примеру по ссылке, этот плагин ломает код. При преобразовании URL.createObjectURL(blob) в .then(URL.createObjectURL) у метода createObjectURL теряется контест (this). И если конкретно для этого метода контекст не требуется, для других методов это не так.

Sign up to leave a comment.

Articles