javascript 如果你不解决或拒绝一个承诺会发生什么?

v2g6jxz6  于 2023-02-11  发布在  Java
关注(0)|答案(5)|浏览(98)

我有一个返回承诺的场景,这个承诺基本上是由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,我将重定向到登录页面,承诺既没有解决也没有拒绝。
这段代码可以吗?或者有没有更好的方法来完成它?

polkgigr

polkgigr1#

在Javascript中,承诺只是一个带有属性的对象。它没有什么魔力。因此,未能解析或拒绝承诺只是无法将状态从“挂起”更改为其他任何状态。这在Javascript中不会导致任何基本问题,因为承诺只是一个常规的Javascript对象。如果没有代码引用承诺,承诺仍然会被垃圾收集(即使仍然挂起)。
这里真实的的结果是,如果promise的状态从未更改,这对promise的使用者意味着什么?解析或拒绝转换的任何.then().catch()侦听器将永远不会被调用。大多数使用promise的代码期望它们在将来的某个时候解析或拒绝(这就是为什么承诺被放在首位),如果不这样做,那么代码通常永远不会完成它的工作。
或者,如果代码使用的是await而不是.then(),那么这个函数在await上将永远挂起,函数的其余部分将是死代码,永远不会执行。
有可能你有其他的代码来完成这个任务,而承诺却被放弃了,如果你这样做的话,在Javascript中没有内部问题,但是这不是承诺被设计来工作的方式,通常也不是承诺的消费者期望它们工作的方式。
正如你所看到的,如果状态是401,我重定向到登录页面。承诺既没有解决,也没有拒绝。
这段代码可以吗?或者有没有更好的方法来完成这一点。
在这个特殊的案例中,这是正常的,重定向是一种特殊的情况。重定向到一个新的浏览器页面将完全清除当前页面的状态(包括所有的Javascript状态),所以使用重定向来走捷径,而只留下其他未解决的问题是完全可以的。当新页面开始加载时,系统将完全重新初始化您的Javascript状态,以便清除任何尚未完成的承诺。

9gm1akwq

9gm1akwq2#

我认为“如果我们不解决拒绝问题会发生什么”已经得到了很好的回答-您可以选择是添加.then还是.catch
但是,* 这段代码可以吗?或者有没有更好的方法来完成这个 *。我会说有两件事:
您在new Promise中 Package 了一个Promise,但它不是必需的,并且fetch调用可能失败,您应该对此采取行动,以便您的调用方法不会坐下来等待一个永远不会解决的Promise。
下面是一个例子(我认为这应该适用于您的业务逻辑,但不是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处理程序将永远不会执行。

dy2hfwbg

dy2hfwbg3#

正如其他人所说,如果你不解决/拒绝一个承诺,这确实不是一个真正的问题。无论如何,我会解决你的问题有点不同:

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
        });
    } 
});

这意味着我会拒绝每个坏的响应状态,然后在makeRequesterror handler中处理它。

fnvucqvd

fnvucqvd4#

它可以工作,并且不是真正的问题,除非makeRequest的调用者期望实现承诺,所以,你在这里破坏了契约。
相反,您可以推迟承诺,或者(在本例中)使用状态代码/错误拒绝。

vwhgwdsa

vwhgwdsa5#

ECMAScript规范解释了promise和new Promise()的用途:
Promise是一个对象,用作延迟(可能是异步)计算的最终结果的占位符。

25.6.3.1承诺( 执行人

参数必须是一个函数对象。调用它是为了启动和报告这个Promise对象所代表的可能延迟的操作的完成。
你应该使用promise来获取未来的值。此外,为了保持你的代码简洁和直接,你应该 * 只 * 使用promise来获取未来的值,而不要做其他事情。
由于您还将程序控制流(重定向逻辑)混合到您的承诺的“执行器”逻辑中,因此您的承诺不再是“计算结果的占位符;“相反,它现在是一个伪装成承诺的小JavaScript程序。
因此,我建议不要将这个JavaScript程序 Package 在new Promise()中,而只像编写普通的JavaScript程序一样编写它:

async function makeRequest(url, params) {
  let response = await fetch(url, params);
  let { status } = response;
  if (status >= 200 && status < 300) {
    let data = await response.json();
    successLogic(data);
  } else if (status === 401) {
    redirectToLoginPage();
  } else {
    let error = await response.json()
    if (!error.message) {
      error.message = constants.SERVER_ERROR;
    }
    errorLogic({ status, error });
  }
}

相关问题