5 распространенных ошибок при использовании промисов

В этой статье я расскажу о пяти распространенных ошибках при использовании промисов в JavaScript, чтобы вы могли их избежать.

1. Избегайте ада промисов

Содержание статьи:

Обычно промисы используются, чтобы избежать ада обратных вызовов. Но неправильное их использование может само вызвать ад.

JavaScript userLogin(‘user’).then(function(user){ getArticle(user).then(function(articles){ showArticle(articles).then(function(){ //Your code goes here… }); }); });

1234567 userLogin(‘user’).then(function(user){    getArticle(user).then(function(articles){        showArticle(articles).then(function(){            //Your code goes here…        });    });});

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

В приведенном выше примере мы имеем три промиса — userLogin, getArticle и showArticle. Как видите, сложность будет расти пропорционально количеству строк кода, и он может стать нечитаемым.

Чтобы избежать этого, нам нужно отменить вложенность кода, вызвав getArticle из первого then и обработать его во втором then.

JavaScript userLogin(‘user’) .then(getArticle) .then(showArticle) .then(function(){ //Your code goes here… });

123456 userLogin(‘user’)  .then(getArticle)  .then(showArticle)  .then(function(){       //Your code goes here…});

2. Использование блока try / catch внутри определения промисов

Обычно мы используем блок try / catch для обработки ошибок. Однако использование try / catch в объекте Promise не рекомендуется. Это потому, что если будут какие-либо ошибки, объект Promise автоматически обработает их в блоке catch.

JavaScript new Promise((resolve, reject) => { try { const data = doThis(); // do something resolve(); } catch (e) { reject(e); } }) .then(data => console.log(data)) .catch(error => console.log(error));

1234567891011 new Promise((resolve, reject) => {  try {    const data = doThis();    // do something    resolve();  } catch (e) {    reject(e);  }})  .then(data => console.log(data))  .catch(error => console.log(error));

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

JavaScript new Promise((resolve, reject) => { const data = doThis(); // do something resolve() }) .then(data => console.log(data)) .catch(error => console.log(error));

1234567 new Promise((resolve, reject) => {  const data = doThis();  // do something  resolve()})  .then(data => console.log(data))  .catch(error => console.log(error));

Примечание. Очень важно использовать .catch () в блоке Promise. В противном случае ваш код может завершиться с ошибкой, а также может произойти сбой приложения на этапе продакшена.

Это всегда будет работать, за исключением следующей ошибки, которую я собираюсь обсудить ниже.

3. Использование асинхронной функции внутри блока Promise

Async / Await — это более продвинутый синтаксис для работы с несколькими промисами в синхронном коде. Когда мы используем ключевое слово async перед объявлением функции, оно возвращает Promise, и мы можем использовать await, чтобы остановить выполнение кода, пока обещание, которое мы ждем, не разрешится или не будет отклонено.

Но есть некоторые побочные эффекты функции Async, когда вы помещаете ее в блок Promise. Представим, что вы хотите выполнить асинхронную операцию в блоке Promise, добавляете ключевое слово async, и ваш код выдает ошибку. Даже если вы используете блок catch () или ждете промис внутри блока try / catch, вы не сможете сразу обработать эту ошибку. Посмотрите следующий пример:

JavaScript // This code can’t handle the error new Promise(async () => { throw new Error(‘message’); }).catch(e => console.log(e.message)); (async () => { try { await new Promise(async () => { throw new Error(‘message’); }); } catch (e) { console.log(e.message); } })();

12345678910111213141516 // This code can’t handle the errornew Promise(async () => {  throw new Error(‘message’);}).catch(e => console.log(e.message));   (async () => {  try {    await new Promise(async () => {      throw new Error(‘message’);    });  } catch (e) {    console.log(e.message);  }})();

Когда я сталкиваюсь с асинхронными функциями внутри блока Promise, я пытаюсь сохранить асинхронную логику вне блока Promise, чтобы поддерживать ее синхронность. И это срабатывает 9 раз из 10. Однако в некоторых случаях может потребоваться асинхронная функция. В этой ситуации у вас не будет другого выбора, кроме как управлять этим с помощью блока try / catch вручную.

JavaScript. Быстрый старт

Изучите основы JavaScript на практическом примере по созданию веб-приложения

JavaScript new Promise(async (resolve, reject) => { try { throw new Error(‘message’); } catch (error) { reject(error); } }).catch(e => console.log(e.message)); //using async/await (async () => { try { await new Promise(async (resolve, reject) => { try { throw new Error(‘message’); } catch (error) { reject(error); } }); } catch (e) { console.log(e.message); } })();

1234567891011121314151617181920212223 new Promise(async (resolve, reject) => {  try {    throw new Error(‘message’);  } catch (error) {    reject(error);  }}).catch(e => console.log(e.message));  //using async/await(async () => {  try {    await new Promise(async (resolve, reject) => {      try {        throw new Error(‘message’);      } catch (error) {        reject(error);      }    });  } catch (e) {    console.log(e.message);  }})();

4. Выполнение блока промиса сразу после его создания

Что касается приведенного ниже фрагмента кода, если мы поместим фрагмент кода для выполнения HTTP-запроса, он будет выполнен немедленно.

JavaScript const myPromise = new Promise(resolve => { // code to make HTTP request resolve(result); });

1234 const myPromise = new Promise(resolve => {  // code to make HTTP request  resolve(result);});

Причина в том, что фрагмент кода заключен в конструктор Promise. Тем не мение, некоторые из вас могут захотеть выполнить myPromise позже. Однако это не так. Вместо этого, когда создается промис, немедленно выполняется обратный вызов.

Это означает, что к тому времени, когда вы перейдете к следующей строке после создания myPromise, ваш HTTP-запрос, скорее всего, уже будет запущен или, по крайней мере, в запланированном состоянии.

Но что вам делать, если вы хотите выполнить промис позже? Что делать, если вы не хотите делать HTTP-запрос прямо сейчас? Есть ли какой-нибудь магический механизм, встроенный в промисы, который позволил бы вам это сделать?

Ответ часто оказывается более очевидным, чем ожидают разработчики. Функции — это трудоемкий механизм. Они выполняются только тогда, когда разработчик явно вызывает их с помощью (). Простое определение функции пока ни к чему не приведет. Итак, самый эффективный способ отложить выполнение Promise — это заключить его в функцию!

JavaScript const createMyPromise = () => new Promise(resolve => { // HTTP request resolve(result); });

1234 const createMyPromise = () => new Promise(resolve => {  // HTTP request  resolve(result);});

Конструктор промисов внутри функции, и в нашей модели пока еще ничего не было вызвано. Мы меняем имя переменной, так как это больше не Promise, а создается и возвращается объект Promise.

С HTTP-запросом конструктор Promise и функция обратного вызова будут вызываться только при выполнении функции. Итак, теперь у нас есть lazy промис, который выполняется только тогда, когда он нам нужен.

5. Не обязательно использовать метод Promise.all()

Если вы профессиональный разработчик, вы уже понимаете, о чем я говорю. Если у вас есть несколько промисов, которые не связаны друг с другом, вы можете выполнить их все одновременно.

Промисы выполняются одновременно, но если вы будете ждать их по одному, это займет слишком много времени. Вы сэкономите много времени, используя Promise.all(). Помните, Promise.all() — ваш друг!!!

JavaScript const { promisify } = require(‘util’); const sleep = promisify(setTimeout); async function f1() { await sleep(1000); } async function f2() { await sleep(2000); } async function f3() { await sleep(3000); } (async () => { console.time(‘sequential’); await f1(); await f2(); await f3(); console.timeEnd(‘sequential’); })();

1234567891011121314151617181920212223 const { promisify } = require(‘util’);const sleep = promisify(setTimeout); async function f1() {  await sleep(1000);} async function f2() {  await sleep(2000);} async function f3() {  await sleep(3000);}  (async () => {  console.time(‘sequential’);  await f1();  await f2();  await f3();  console.timeEnd(‘sequential’);  })();

Выполнение приведенного выше кода займет около 6 секунд, но если мы заменим его на Promise.all(), это сократит время выполнения.

JavaScript (async () => { console.time(‘concurrent’); await Promise.all([f1(), f2(), f3()]); console.timeEnd(‘concurrent’); })();

12345 (async () => {    console.time(‘concurrent’);    await Promise.all([f1(), f2(), f3()]);    console.timeEnd(‘concurrent’);   })();

Заключение

В этой статье я рассказал о пяти типичных ошибках, которые делают разработчики при использовании промисов в JavaScript. Однако может быть гораздо больше вопросов, требующих тщательного решения. Удачного кодирования.

Автор: Ravidu Perera

Источник: webformyself.com

Comments (0)
Add Comment