Асинхронный JavaScript - обратные вызовы против отложенных / обещаний

Возможный дубликат:
В чем разница между отложенным, обещанием и будущим в Javascript?

В последнее время я стараюсь улучшить качество своих приложений JavaScript.

Один из шаблонов, который я принял, - это использование отдельного объекта «контекста данных» для загрузки данных для моего приложения (раньше я делал это непосредственно в своих моделях представления).

В следующем примере возвращаются данные, инициализированные на клиенте:

var mockData = (function($, undefined) {

    var fruit = [
        "apple",
        "orange",
        "banana",
        "pear"
        ];

    var getFruit = function() {
        return fruit;
    };

    return {
        getFruit: getFruit
    }
})(jQuery);

В большинстве случаев мы загружаем данные с сервера, поэтому мы не можем сразу же вернуть ответ. Кажется, у меня есть два варианта того, как мы справимся с этим в нашем API:

  1. Использование обратного вызова
  2. Возврат обещания.

Раньше я всегда использовал обратный вызов:

var getFruit = function(onFruitReady) {
    onFruitReady(fruit);
};

// ...

var FruitModel = function(dataContext, $) {
    return {
        render: function() {
            dataContext.getFruit(function(fruit) {
                // do something with fruit
            });
        }
    };
};

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

Затем я наткнулся на шаблон проектирования Promises. Вместо того, чтобы требовать от вызывающего абонента предоставить обратный вызов, я вместо этого возвращаю "обещание", которое можно наблюдать:

var getFruit = function() {
    return $.Deferred().resolve(fruit).promise();
};

// ...
dataContext.getFruit().then(function(fruit) {
    // do something with fruit
});

Я вижу очевидные преимущества использования этого шаблона, особенно потому, что я могу wait работать с несколькими отложенными объектами, что может быть очень полезно при загрузке данных инициализации для одностраничного приложения.

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

Вот ссылка на скрипт, который я использую для тестирования.


person Ben Foster    schedule 02.01.2013    source источник
comment
Что ж, хорошие новости: API jQuery ajax уже возвращают обещания!   -  person Pointy    schedule 02.01.2013
comment
Прочтите этот механизм здесь.   -  person Pointy    schedule 02.01.2013
comment
Да, именно так я впервые столкнулся с шаблоном, когда искал способ абстрагировать свои вызовы ajax.   -  person Ben Foster    schedule 02.01.2013
comment
Я думаю, что обратные вызовы немного быстрее, но мне очень нравится ваш вопрос, и я заинтересован в ответе!   -  person hereandnow78    schedule 02.01.2013
comment
Ах. Я имею в виду, что вам действительно не нужно много добавлять; значения, возвращаемые этими вызовами, готовы к использованию, поэтому нужно просто избавиться от привычки передавать успешные обратные вызовы и получить в привычку вызывать .done() и т. д.   -  person Pointy    schedule 02.01.2013
comment
@jbabey Я спрашиваю, каковы плюсы и минусы использования обратных вызовов vs Deferred / Promise, так что это совсем другой вопрос.   -  person Ben Foster    schedule 02.01.2013
comment
В angularjs есть хорошая концепция получения ресурсов на стороне сервера: docs.angularjs.org/tutorial/step_05   -  person Amir    schedule 02.01.2013
comment
@jbabey не дубликат: deferred / обещание / будущее относятся к шаблону обещаний, OP запрашивает сравнение с прямыми обратными вызовами.   -  person Christophe    schedule 02.01.2013
comment
@BenFoster, вопрос плохо назван - прочтите ответы, поскольку они, кажется, отвечают именно на то, что вы спрашиваете. Вместо того, чтобы напрямую передавать обратные вызовы функциям, что может привести к тесно связанным интерфейсам, использование обещаний позволяет разделить проблемы для кода, который является синхронным или асинхронным.   -  person jbabey    schedule 02.01.2013
comment
@jbabey Этот вопрос принципиально отличается от другого, помеченного как повторяющийся. Обратные вызовы - это совершенно другой механизм, чем фьючерсы / обещания, и отметка этого вопроса как дубликата создает серьезную пагубную путаницу для любого, кто пытается узнать о различиях между этими концепциями.   -  person Levi Lindsey    schedule 18.06.2014
comment
Ссылка: softwareengineering.stackexchange.com/questions/302455/   -  person Mahesh K    schedule 26.10.2016


Ответы (2)


Обещания также полагаются на обратные вызовы за сценой, поэтому на самом деле это не одно против другого.

Преимущество обратных вызовов заключается в том, что их легко реализовать с помощью простого JavaScript (например, в вызовах ajax).

Обещания требуют дополнительного уровня абстракции, что обычно означает, что вы будете полагаться на библиотеку (в вашем случае это не проблема, поскольку вы уже используете jQuery). Они идеальны, когда вы имеете дело с несколькими асинхронными вызовами параллельно.

person Christophe    schedule 02.01.2013
comment
Обратите внимание, что с марта 2014 года браузеры начали реализовывать собственные обещания, поэтому мое утверждение справедливо только для полифиллов. - person Christophe; 25.04.2014

Читая документы jQuery, на которые ссылается @Pointy, кажется, что разница в том, что Deferred API позволяет вам указать более одной функции, которая будет вызываться после завершения вашего запроса:

Начиная с jQuery 1.5, хуки обратного вызова error (fail), success (done) и complete (всегда, начиная с jQuery 1.6) являются управляемыми очередями «первым пришел - первым обслужен». Это означает, что вы можете назначить более одного обратного вызова для каждой ловушки. См. Отложенные методы объекта, которые реализованы внутри для этих хуков обратного вызова $ .ajax ().

См. Также: deferred.then ()

person Max Fellows    schedule 02.01.2013
comment
Дело не в том, что Deferreds / promises позволяют вам указать более одной функции, которая будет вызываться, настолько, насколько они делают это проще. Конкретные особенности заключаются в том, что (а) функции могут быть добавлены (например, с .done() или .fail()) в любом месте кода, при условии, что отложенное / обещание находится в пределах области действия, и (б) функции, добавленные после разрешения / отклонения отложенного, будут немедленно стрелять. Предоставляя внутреннюю .Callbacks() утилиту, jQuery делает этот тип функциональности возможной без использования Deferreds / promises, но они избавляют от проблем кодирования / отладки. - person Beetroot-Beetroot; 03.01.2013