Чем отличаеться promise от обычных коллбэков?

Набросал тут вот такой код
function someAsyncFunction(num, callback) {
    setTimeout( () => callback(num*2), 1500);
}
function promiseFunction(num) {
    return new Promise((resolve, reject) => {
        setInterval(() => resolve(num*2), 1500)
    });
}

someAsyncFunction(10, res => console.log(res)); // Выведет 20 через 1,5 сек.
promiseFunction(10).then(res => console.log(res)); // Тот же результат

По сути мы делаем одно и то же просто разными способами. В чем принципиальное различие в этих двух подходах? ведь ведь функция resolve это по сути тот же callback который мы используем в первой фнкции
  • Вопрос задан
  • 6189 просмотров
Решения вопроса 1
delphinpro
@delphinpro Куратор тега JavaScript
frontend developer
Не то же самое

function ajax() {
  return fetch(target, fetchOptions)
    .then((response) => {
      if (!target) throw new Error('Invalid url');
      if (response.ok) return response.json();
      throw new Error(`${response.status} ${response.statusText}`);
    })
    .then((json) => {
        if (json['statusOk']) return json;
        throw new Error(json['message'] || 'Server response was not ok');
    });
}

ajax(action, { body: formData })
  .then((json) => {
    console.log('RESPONSE', json);
  })
  .catch((error) => {
    console.error(error);
  });


Мы можем писать сколько угодно зенов, в каждом что-то делать с данными.
Если в любом месте вылетит ошибка, она будет нормально обработана в кэтче.
Код при этом линейный, без дикой вложенности.
С коллбэками вам нужно на каждом этапе отслеживать ошибки и возвращать их. Легко потеряться, что откуда всплыло или где пропало.
Альтернатива обработки ошибок — трай/кэтч. Но это не работает на асинхронном коде.
function myFunc(cb){
  var err = true;
  // имитируем асинхронную операцию
  setTimeout(function(){
    cb(err);
  }, 10);
}

try {
  myFunc(function(err){
    if (err) throw new Error('Oops');
  });
  alert('Всё как бы хорошо!');
} catch(e) {
  alert(e.message);
}

Этот код выведет сообщение 'Всё как бы хорошо!', хотя всё плохо, была ошибка. https://jsfiddle.net/r3zfa4ee/

С промисами иначе:
function myFunc(){
  let promise = new Promise((resolve, reject) => {
    let err = true;
  
    // имитируем асинхронную операцию
    setTimeout(() => {
      if (err) {
        reject('Ooops!');
      } else {
        resolve(123);
      }
    }, 10);
  });
  
  return promise;
}

myFunc()
  .then(data => {
    alert('Всё точно хорошо!');
  })
  .catch(e => {
    alert(e);
  });

Здесь уже ошибка будет обработана как надо и мы увидим сообщение 'Ooops!' https://jsfiddle.net/43yh8jad/

Мы можем выполнить промисы последовательно. Мы можем выполнить их параллельно. Мы можем запустить их на параллельное выполнение, но дождаться только первого отработавшего (так называемая promise race). Разумеется всё это можно и без промисов написать, но какая будет разница в объеме кода и в сложности его понимания?

А еще есть async/await...
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 3
k12th
@k12th
console.log(`You're pulling my leg, right?`);
Два главных отличия:
  1. Promise это значение (точнее, обертка над нужным нам значением), а не кусок кода, со всеми вытекающими. Можно передавать, возвращать из функции и так далее. Это теоретически возможно и с коллбэками, но будет очень много .bind/.call/.apply и прочей функциональщины отнюдь не упрощающей чтение кода.
  2. Promise из коробки позволяет легко связывать асинхронные операции в цепочки. Опять таки это в принципе возможно и с коллбэками, но нужна сторонняя либа, например async, нужно помнить её методы, лишняя зависимость и т.д.


Принципиальных отличий нет, оба подхода базируются на том, как работает в JS event loop и на том, что функции там граждане первого класса. Просто с промизами работать все-таки приятнее.
Ответ написан
Комментировать
Кучей всяких методов bluebirdjs.com/docs/api-reference.html
И ненужностью передавать ошибки первым аргументом
Ответ написан
@LiguidCool
Если кратко - особо ничем. Это просто "сахар", несколько упрощают работу и понимание кода.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы