Что произойдет, если мы не разрешим или не отклоним обещание

У меня есть сценарий, когда я возвращаю обещание. Обещание в основном дает ответ на запрос ajax.

При отказе от обещания отображается диалоговое окно с сообщением об ошибке сервера.

То, что я хочу сделать, - это когда код ответа 401, я не хочу разрешать обещание и не отклонять его (потому что он показывает диалоговое окно с ошибкой). Я хочу просто перенаправить на страницу входа.

Мой код выглядит примерно так:

function makeRequest(ur,params) {

    return new Promise(function(resolve,reject) {

        fetch(url,params)
        .then((response) => {

            let status = response.status;

            if (status >= 200 && status < 300) {
                response.json().then((data) => {
                    resolve(data);
                })
            }
            else {
                if(status === 401) {
                    redirectToLoginPage();
                }
                else {
                    response.json().then((error) => {

                        if (!error.message) {
                            error.message = constants.SERVER_ERROR;
                        }
                        reject({status,error});
                    })    
                }
            }

        })
    });
}

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

Этот код в порядке? Или есть лучший способ сделать это.

Спасибо.

Ответ 1

Обещание - это просто объект со свойствами в Javascript. Там нет магии к этому. Таким образом, неспособность разрешить или отклонить обещание просто не в состоянии изменить состояние с "ожидания" на что-либо еще. Это не вызывает каких-либо фундаментальных проблем в Javascript, потому что обещание - это просто обычный объект Javascript. Обещание по-прежнему будет собирать мусор (даже если оно еще не выполнено), если ни один код не содержит ссылку на обещание.

Реальное следствие здесь состоит в том, что это означает для потребителя обещания, если его состояние никогда не изменяется? Любые слушатели .then() или .catch() для переходов разрешения или отклонения никогда не будут вызваны. Большая часть кода, использующего обещания, ожидает, что они разрешат или отклонят в какой-то момент в будущем (именно поэтому обещания используются в первую очередь). Если они этого не делают, то этот код обычно никогда не завершает свою работу.

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

Как вы можете видеть, если статус 401, я перенаправляю на страницу входа. Обещание не решено и не отклонено.

Этот код в порядке? Или есть лучший способ сделать это.

В этом конкретном случае все в порядке, и перенаправление - это особый и уникальный случай. Перенаправление на новую страницу браузера полностью очистит текущее состояние страницы (включая все состояния Javascript), поэтому вполне нормально использовать ярлык с перенаправлением и просто оставить другие вещи нерешенными. Система полностью переинициализирует ваше состояние Javascript, когда новая страница начнет загружаться, поэтому все обещания, которые еще ожидают, будут очищены.

Ответ 2

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

Ответ 3

Я думаю, что "что происходит, если мы не разрешаем отклонение", ответили хорошо - это ваш выбор: добавить ли .then или .catch.

Однако, этот код в порядке? Или есть лучший способ сделать это. Я бы сказал, что есть две вещи:

Вы обмениваете Promise в new Promise, когда это не нужно, и вызов fetch может выйти из строя, вы должны действовать так, чтобы ваш метод вызова не сидел и не ждал обещание, которое никогда не будет разрешено.

Вот пример (я думаю, что это должно работать для вашей бизнес-логики, а не на 100%):

const constants = {
  SERVER_ERROR: "500 Server Error"
};
function makeRequest(url,params) {
  // fetch already returns a Promise itself
  return fetch(url,params)
        .then((response) => {

            let status = response.status;

            // If status is forbidden, redirect to Login & return nothing,
            // indicating the end of the Promise chain
            if(status === 401) {
              redirectToLoginPage();
              return;
            }
            // If status is success, return a JSON Promise
            if(status >= 200 && status < 300) {
              return response.json();
            }
            // If status is a failure, get the JSON Promise,
            // map the message & status, then Reject the promise
            return response.json()
              .then(json => {
                if (!json.message) {
                    json.message = constants.SERVER_ERROR;
                }
                return Promise.reject({status, error: json.message});
              })
        });
}
// This can now be used as:
makeRequest("http://example", {})
  .then(json => {
    if(typeof json === "undefined") {
      // Redirect request occurred
    }
    console.log("Success:", json);
  })
  .catch(error => {
    console.log("Error:", error.status, error.message);
  })

В отличие от этого, вызывая свой код, используя:

makeRequest("http://example", {})
  .then(info => console.log("info", info))
  .catch(err => console.log("error", err));

Не будет записывать ничего, потому что вызов http://example завершится с ошибкой, но обработчик catch никогда не выполнится.

Ответ 4

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

Вместо этого вы можете отложить обещание или (в этом случае) отказаться от кода состояния/ошибки.

Ответ 5

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

function makeRequest(ur,params) {

    return new Promise(function(resolve,reject) {

        fetch(url,params)
        .then((response) => {

            let status = response.status;

            if (status >= 200 && status < 300) {
                response.json().then((data) => {
                    resolve(data);
                })
            }
            else {
                reject(response);
            }
        })
    });
}

makeRequest().then(function success(data) {
   //...
}, function error(response) {
    if (response.status === 401) {
        redirectToLoginPage();
    }
    else {
        response.json().then((error) => {
            if (!error.message) {
                error.message = constants.SERVER_ERROR;
            }

            //do sth. with error
        });
    } 
});

Это означает, что я отклоняю каждое состояние плохого ответа, а затем обрабатываю это в error handler вашего makeRequest.