Подтвердить что ты не робот

Почему мы предпочитаем использовать $q в angular вместо $http

В настоящее время я использую службу $q из angular, чтобы вызвать вызовы API следующим образом:

var deferred = $q.defer();
$http.get(config.apiHost + details.url)
    .success(function (data) {
        deferred.resolve(data);
    }).error(function (msg) {
        deferred.reject(msg);
    });
return deferred.promise;

но мы также можем использовать этот подход, не используя $q:

return $http.get(config.apiHost + details.url)
    .success(function (data) {
        return data;
    }).error(function (msg) {
        return msg;
    });

и поскольку $http сам возвращает обещание, я также могу использовать более упрощенный подход:

$http.get(config.apiHost + 'posts')
        .success(function (data) {
            console.log(data)
        }).error(function (msg) {
            console.log(msg);
        });

Так в чем же разница между этими особенностями между $q и $http, так как обе дают обещание, и оба они async? Имеет ли angular дополнительную функциональность с помощью $q? Я не могу найти хороший ответ.

4b9b3361

Ответ 1

$q в основном используется только для совместимости с библиотеками, которые по умолчанию не поддерживают promises, и когда вы не можете полагаться на собственную реализацию Promise (например, в старых браузерах, таких как IE9). Нет причин (для вас) использовать его иначе. Например, если вы хотите сделать основанную на обещаниях $timeout. $http сам использует $q под капотом по этим точным причинам.

В отличие от того, что предложили другие (после удаления) ответы, вам не нужно использовать $q, чтобы "сохранить" результат обещания $http. Я бы не рекомендовал хранить обещание вообще (поскольку это имеет тенденцию приводить к коду спагетти), но если вы должны это сделать абсолютно, вы можете просто сохранить результирующее обещание от $http; promises выполняется только один раз.

Любые функции, переданные в then после того, как обещание разрешилось/отклонено, будет разрешено на следующем тике, без повторного вызова первоначального действия, которое создало обещание в первую очередь - IOW, результат обещания будет сохранен в памяти внутри этого объекта.

Также обратите внимание, что цепочка promises, которая недоступна для этого ответа, но по существу означает, что следующие фрагменты кода эквивалентны

function legacyGet() {
  const deferred = $q.defer()
  $http.get('http://www.google.com')
    .then((response) => deferred.resolve(Object.assign(response, {foo: bar}))
    .catch((error) => deferred.reject(error))
  return deferred.defer
}

function modernGet() {
  return $http.get('http://www.google.com')
    .then((response) => Object.assign(response, {foo: bar}))
}

Подводя итог: Ваше название неверно. Мы не предпочитаем использовать $q, мы используем его только экономно. Предпочитаете использовать ES6 Promise, если вам не нужно поддерживать браузеры, у которых его нет, и вы не можете использовать polyfill.

Ответ 2

$http использует $q, первый пример является избыточным, а также вторым. Вам просто нужно вернуть обещание, что $http.get возвращает:

return $http.get(config.apiHost + details.url);

Вышеупомянутое совпадает с вашим первым фрагментом кода.

Кроме того, return msg не совпадает с deferred.reject(msg). Эквивалентом будет throw msg или return $q.reject(msg)

Еще одно замечание: success и error являются нестандартными, вы хотите использовать then и catch.

Ответ 3

В angular в основном все службы возвращают только promises, но есть несколько случаев, когда вы хотели бы создать свой собственный отложенный объект с помощью $q.

Случай 1

Когда вы используете библиотеку, которая не поддерживает обещание или вы создали свою собственную функцию и хотите вернуть обещание.

Случай 2

Когда вы используете любую конструкцию, которая по умолчанию возвращает обещание, но вы хотите вернуть отдельное обещание, основанное на некоторых в каком-то определенном состоянии.

Пример: В angular $http возвращается только обещание, но теперь, если вы хотите, чтобы ответ на это обещание содержал конкретное значение, тогда только вы хотите вернуть разрешенное else return fail, тогда вам нужно создать свой собственный deffered object и его нужно разрешить или скомпрометировать на основе значения, возвращаемого ответом $http.