You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多异步Fetch请求致函数执行挂起问题排查

问题

开发注册组件时,流程为:

  1. 调用uploadUser函数将用户数据插入数据库,成功返回用户ID,失败返回false;
  2. 若ID存在,将图片上传至Firebase获取URL,再调用upload-user-image接口结合ID更新数据库中的用户URL。

但navigate("/email-approval")始终未执行,浏览器网络面板显示upload-user-image请求已完成图片上传,但请求状态长期处于pending甚至永久pending,异步操作停滞。

相关代码如下:

const uploadUser = async () => {
  setDisableBtn(true);
  const user = {
    firstName: userData.firstName,
    lastName: userData.lastName,
    email: `${userData.email}@bushnaq.group`,
    password: userData.password,
    gender: userData.gender,
    birthDate: userData.birthDate,
    image: "placeholder",
  };

  const res = await fetch("http://localhost:8000/api/signup", {
    method: "POST",
    body: JSON.stringify(user),
    headers: { "Content-Type": "application/json" },
  });
  const data = await res.json();
  if (data.status === 400) {
    setDisableBtn(false);
    setErrSignup(data.message);
    return false;
  }
  return data.id;
};

const handleSubmit = async (e) => {
  e.preventDefault();

  let errors = {};

  if (
    userData.image.type !== "image/jpeg" &&
    userData.image.type !== "image/png"
  ) {
    errors.errImg = "Profile picture must have JPEG or PNG extensions.";
  }

  if (
    userData.firstName.length > 15 ||
    userData.lastName.length > 15 ||
    userData.firstName.length < 3 ||
    userData.lastName.length < 3
  ) {
    errors.errName =
      "First name and/or must be between 3 and 15 characters in length.";
  }
  if (userData.email.length > 25) {
    errors.errEmail = "Email is too long.";
  }

  if (userData.email.includes("@")) {
    errors.errEmail = "Email must not contain @ sign.";
  }

  if (!isPasswordStrong(userData.password)) {
    errors.errPs =
      "Please use a password that contains at least one number, one uppercase letter and at least 8 chatacters in length.";
  }

  if (userData.password !== userData.confirmPassword) {
    errors.errCp = "Passwords do not match.";
  }

  if (!userData.gender) {
    errors.errGender = "Gender must not be empty.";
  }

  setErrors(errors);

  if (!Object.keys(errors).length) {
    const id = await uploadUser();
    if (id) {
      const imageRef = storageRef(storage, `images/${Date.now()}`);
      const snapshot = await uploadBytes(imageRef, userData.image);
      const url = await getDownloadURL(snapshot.ref);
      const res = await fetch("http://localhost:8000/api/upload-user-image", {
        method: "PUT",
        body: JSON.stringify({
          id: id,
          url: url,
        }),
        headers: { "Content-Type": "application/json" },
      });
      const data = await res.json();
      if (data.status === 400) {
        setErrSignup(data.message);
      } else {
        console.log("done");
        navigate("/email-approval");
      }
    }
  }
};

问题分析与解决方案

1. 后端接口未返回响应

网络请求pending的核心原因大概率是后端upload-user-image接口未正确发送HTTP响应。比如后端完成数据库更新后,遗漏了res.send()/res.json()这类响应语句,导致前端的fetch一直处于等待状态,代码卡在await res.json()这一步,无法执行后续的else分支。

  • 检查后端upload-user-image接口代码,确保无论处理成功还是失败,都返回明确的响应。比如成功时返回:
    res.json({ status: 200, message: "用户图片URL更新成功" });
    
    失败时返回对应错误状态码和信息。

2. 缺失错误捕获逻辑

当前代码未对fetch请求做异常捕获,如果upload-user-image请求出现网络错误(如后端崩溃、跨域问题),await会直接抛出异常,导致代码中断,无法走到else分支。

  • 给upload-user-image的请求添加try/catch,并检查响应是否正常:
    try {
      const res = await fetch("http://localhost:8000/api/upload-user-image", {
        method: "PUT",
        body: JSON.stringify({ id, url }),
        headers: { "Content-Type": "application/json" },
      });
      // 先判断响应状态是否正常
      if (!res.ok) throw new Error(`请求失败,状态码:${res.status}`);
      const data = await res.json();
      if (data.status === 400) {
        setErrSignup(data.message);
      } else {
        console.log("done");
        navigate("/email-approval");
      }
    } catch (err) {
      console.error("更新用户图片URL失败:", err);
      setErrSignup("图片信息更新失败,请重试");
      setDisableBtn(false);
    }
    

3. uploadUser函数的异常处理缺失

uploadUser中的fetch同样没有错误捕获,如果注册请求出现网络错误,会直接抛出异常,导致handleSubmit后续逻辑中断。

  • 给uploadUser添加try/catch:
    const uploadUser = async () => {
      setDisableBtn(true);
      try {
        const user = {
          firstName: userData.firstName,
          lastName: userData.lastName,
          email: `${userData.email}@bushnaq.group`,
          password: userData.password,
          gender: userData.gender,
          birthDate: userData.birthDate,
          image: "placeholder",
        };
    
        const res = await fetch("http://localhost:8000/api/signup", {
          method: "POST",
          body: JSON.stringify(user),
          headers: { "Content-Type": "application/json" },
        });
        if (!res.ok) throw new Error(`注册请求失败,状态码:${res.status}`);
        const data = await res.json();
        if (data.status === 400) {
          setDisableBtn(false);
          setErrSignup(data.message);
          return false;
        }
        return data.id;
      } catch (err) {
        console.error("注册失败:", err);
        setDisableBtn(false);
        setErrSignup("注册失败,请检查网络或输入信息");
        return false;
      }
    };
    

4. Firebase操作的潜在问题

虽然Firebase的uploadBytes和getDownloadURL显示完成,但如果存在未释放的资源或未处理的异步任务,也可能间接影响后续请求。不过结合现象来看,主要问题还是集中在后端接口响应和前端错误捕获上。


内容的提问来源于stack exchange,提问作者Aasem Shoshari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 18:55:14