Как вернуть обещание из .then

Я хочу иметь возможность связывать обещания, чтобы сделать код синхронным. Моя проблема в том, что в зависимости от результата первого запроса $http я могу либо захотеть отправить другой, либо нет. В случае, если я решу не отправлять еще один запрос $http, мне не нужно, чтобы мой второй then() что-либо делал. Но так как мой второй then() не знает обо всем этом, и он все равно там висит, поэтому я решил, что мне нужно вернуться с первого, а затем какое-то фальшивое фиктивное обещание. Но я также хотел бы распознать этот случай во втором then() . Я придумал возвращать $q.when('какое-то значение') из первого случая. Вот код:

$http.get(url, params)
    .then(function(res) {
        res = res.data;
        if (res.status == 'ok' && res.rows.length > 0) {
            $scope.roomTypes = res.rows;
            return $q.when({ isDummy: true }); //in this case I don't need to send another request
        } else if (res.rows.length === 0 && $scope.request.roomType) {
            return $http.get(url2, params2); //make second request and return then`able promise
        }
    }, function(res) {
        throw 'Error';
    })
    .then(function(res) {
        res = res.data;
        if (res.status == 'ok') {
            var roomType = {
                room_type: res.roomType.id,
                description: res.roomType.description
            };
            $scope.roomTypes.push(roomType);
        } else if (res.isDummy) {
            //ok that's our dummy promise 
        } else {
            //format of response unexpected it means something went wrong
            throw "error";
        }
    }, funcrtion(res) {
        throw "some Error";
    })
    .catch(function(res) {...})
    .finally(function() {...});

Дело в том, что я хочу увидеть значение, с которым обещание было разрешено ({isDummy: true}), но как мне это сделать? Я получаю undefined в своем параметре res.


person dKab    schedule 22.09.2015    source источник
comment
В вашем коде опечатка: funcrtion   -  person rmorrin    schedule 22.09.2015


Ответы (5)


res здесь не будет определено

      .then(function(res) {
        res = res.data;
        ...

потому что в объекте {isDummy: true} нет свойства data.

person Estus Flask    schedule 22.09.2015
comment
res.data должно быть неопределенным. Но сам res не должен. - person rmorrin; 22.09.2015
comment
он назначен res.data. Отсюда и проблема. - person Estus Flask; 22.09.2015
comment
@rmorrin, эстус, вы мои герои! - person dKab; 22.09.2015

Я думаю, что основной проблемой здесь является путаница промисов с обработчиками промисов. Обработчики успеха должны возвращать значение, а не другое обещание. Когда вы находитесь в обработчике успеха обещания, вы «обертываетесь» механизмом обещания, который принимает возвращаемое вами значение и передает его следующему обработчику. Это означает, что ваше второе обещание видит не первоначальный ответ, а то, что вернуло первое обещание.

Значение обрабатывается по мере его поступления, если только вы не передадите его как есть.

Например, это все сводится к тому, что ваша линия

return $q.when({isDummy: true});

Должно быть

return {isDummy: true};

Проблема заключается в другом случае, когда вы хотите перейти к следующему запросу. Я бы, вероятно, сделал одно из следующих действий: 1. Запустил обработку первого промиса (с соответствующей логикой из первого обработчика). 2. Передайте url2 и params — return({url: url2, params: params}) и обработайте их во втором промисе.

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

person Meir    schedule 22.09.2015

Попробуйте вернуть любой объект, кроме promise или deferred :) И его значение будет передано в then. Как это:

return { isDummy: true };

Пример кода: https://jsfiddle.net/817pwvus/

Из jQuery when документации:

Если в jQuery.when() передается один аргумент, и он не является Deferred или Promise, он будет рассматриваться как разрешенный Deferred, и любые прикрепленные doneCallbacks будут выполняться немедленно. В doneCallbacks передается исходный аргумент.

person kirschpirogge    schedule 22.09.2015

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

если вы хотите связать обещание (Post:url1)->(Post:url2) и так далее:

1.Возврат бесполезен. 2. Предположим, у вас есть 2 промиса $http, которые вы хотите связать, оба из службы с именем $users, например, и они вызвали GetUserAge и GetRelevantBars, а второй запрос основан на результатах первого.

angular
 .module("moduleA")
 .controller("exmapleCtrl",exampleCtrl);

exampleCtrl.$injector=["$users"];

function exampleCtrl($users){
 var vm=this;

 vm.query = $users.GetUserAge().then( /*OnSuccess*/ GetUserAgeCB)

 //Callback of the GetUserAgeCB;
 function GetUserAgeCB(result){
  $users.GetRelevantBars().then( /*OnSuccess*/ GetRelevantBarsCB);
  /*continuation of CallBack code*/
 }


 //Callback of the GetRelevantBarsCB;
 function GetRelevantBarsCB(result){
  /*CallBack code*/
 }

}

надеюсь это понятно..

person Lior Ben Aharon    schedule 22.09.2015

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

$http.get(url, params)
.then(function(res) {
    var data = res.data;
    if (data.status == 'ok' && data.rows.length > 0) {
        $scope.roomTypes = data.rows;
        return; // do nothing
    } else if (res.rows.length === 0 && $scope.request.roomType) {
        return $http.get(url2, params2)
        .then(function(res) {
            var data = res.data;
            if (data.status == 'ok')
                $scope.roomTypes.push({
                    room_type: data.roomType.id,
                    description: data.roomType.description
                });
            else
                throw "error";  //format of response unexpected it means something went wrong
        });
    }
})
.catch(function(res) {…})
.finally(function() {…});
person Bergi    schedule 22.09.2015