Javascript 异步等待未按预期工作:ReactJS

Javascript 异步等待未按预期工作:ReactJS,javascript,reactjs,ecmascript-6,async-await,react-router,Javascript,Reactjs,Ecmascript 6,Async Await,React Router,我有这个问题,在,用户必须重定向到相应的仪表板成功登录。假设用户在两个配置文件“p1”和“p2”中拥有帐户。登录成功后,我正在制作FetchAPI以查看用户是否有相应的配置文件条目 1) 假设用户在p1中有条目,我需要将其重定向到“p1”仪表板 2) 如果输入p2,则将其重定向到“p2”仪表板 3) 如果p1或p2中都不存在条目,则重定向到配置页面,他可以在其中创建一些条目 4) 如果在这两个配置文件中,则会要求用户选择相应的仪表板 现在,在我的例子中,我编写的代码没有按预期工作。尽管我在“p2

我有这个问题,在,用户必须重定向到相应的仪表板成功登录。假设用户在两个配置文件“p1”和“p2”中拥有帐户。登录成功后,我正在制作FetchAPI以查看用户是否有相应的配置文件条目

1) 假设用户在p1中有条目,我需要将其重定向到“p1”仪表板

2) 如果输入p2,则将其重定向到“p2”仪表板

3) 如果p1或p2中都不存在条目,则重定向到配置页面,他可以在其中创建一些条目

4) 如果在这两个配置文件中,则会要求用户选择相应的仪表板

现在,在我的例子中,我编写的代码没有按预期工作。尽管我在“p2”中没有帐户,但在“p1”中有帐户,这会将我带到配置页面。有人能帮我找出代码中的错误吗

注意,fetch调用可以正常工作!它给了我一系列的项目。如果不存在项,则返回空数组

// On login 
  handleLogin = async () => {
        // after successful signin
        await Promise.all([
          this.setDashboard("p1"),
          this.setDashboard("p2"),
        ]);
        this.navigateToDashboards();
  };

   setDashboard = async (profile) => {
    let response, value;
    let type = profile;
    if (type === "p1") {
      response = await this.fetchUserAccounts(type);
      value = !!response && response.length ? true : false;
      this.setState({ isP1: value });
    } else {
      response = await this.fetchUserAccounts(type);
      value = !!response && response.length ? true : false;
      this.setState({ isP2: value });
    }
  };

  fetchUserAccounts = async (type) => {
    try {
      let response = await fetch({
        url: "/fetch/entries",
        method: "POST",
        body: {
          profile: type,
        }
      );
      return response.json();
    } catch (error) {
      console.log(error);
    }
  };


    navigateToDashboards = () => {
    let { isP1, isP2 } = this.state;
    if (isP1 && isP2) {
      // CODE FOR PROMPTING WHICH DASHBOARD TO GO
    } else if (!isP1 && !isP2) {
      this.props.history.push("/configpage"); 
    } else if (isP1) {
      this.props.history.push("/p1dashboard");
    } else if (isP2) {
      this.props.history.push("/p2dashboard");
    }
  };


问题是您使用的
async/await
错误

wait
履行承诺——你给它一个承诺,它等待它解决/拒绝。如果你不给它一个承诺——就像给它一个立即解决的承诺

您的
setDashboard
函数没有承诺,因此发生的情况是此代码:

await Promise.all([
          this.setDashboard("p1"),
          this.setDashboard("p2"),
        ]);
实际上会立即解析,但是直到
this.navigateToDashboards(),才执行
setDashboard
函数。为什么?因为它们被定义为异步的,这将它们放在事件循环中。然后在
await
中出现,但它会立即解析,因为其中的函数不返回承诺(当然,它会,因为它是异步的,但它类似于将
return promise.resolve()
作为第一行写入,因此
await
只会将函数放入事件循环中)-代码继续以同步方式执行,直到到达函数末尾(例如,执行
this.navigateToDashboards();
),然后进入事件循环并执行
setDashboards
函数

在同一主题上,
response=wait this.fetchUserAccounts(type);
行也有多余的wait,因为
fetchUserAccounts()
不返回承诺

要正确使用async/await,请确保
async
函数返回承诺,例如:

setDashboard = async (profile) => {
 return new Promise( resolve, reject => {
    let response, value;
    let type = profile;
    if (type === "p1") {
      response = await this.fetchUserAccounts(type);
      value = !!response && response.length ? true : false;
      this.setState({ isP1: value });
      resolve();
    } else {
      response = await this.fetchUserAccounts(cloudType);
      value = !!response && response.length ? true : false;
      this.setState({ isP2: value });
      resolve();
    }
  })
};
至于fetchUserAccount:

fetchUserAccounts = async (type) => {
  return new Promise( resolve, reject => {
    try {
      let response = await fetch({
        url: "/fetch/entries",
        method: "POST",
        body: {
          profile: type,
        }
      );
      resolve(response.json());
    } catch (error) {
      console.log(error);
      reject(error);
    }
  }
};

请注意,您现在必须使用
.catch
处理承诺拒绝,否则您将得到
未处理的承诺拒绝错误

您上面编写的代码存在一些问题,它们可能比我们在代码段中看到的更深入–为什么要在客户端使用仪表板类型的逻辑让它从服务器上发送

还有
setDashboard
方法中未指定的
cloudType

我不知道您想要实现什么,所以我猜您可能应该在
componentDidMount
中使用
fetchUserAccounts
并将响应保存在状态中

我在代码中找到了这样一个
TODO:

class X extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      p1: null,
      p2: null,
    };
  }

  async componentDidMount() {
    const [p1, p2] = await Promise.all([
      this.fetchUserAccounts('p1'),
      this.fetchUserAccounts('p1'),
    ]);
    // NOTE: setState has a second parameter, which is a callback – this way you make sure that the state has been updated – read more here:
    // https://reactjs.org/docs/react-component.html#setstate
    this.setState(s => ({ ...s, p1, p2 }), this.navigateToDashboards);
  }

  fetchUserAccounts = async (type) => {
    try {
      let response = await fetch({
        url: "/fetch/entries",
        method: "POST",
        body: {
          profile: type,
        },
      });
      return response.json();
    } catch (error) {
      console.log(error);
    }
  };

  navigateToDashboards = () => {
    const { history } = this.props;
    const { p1, p2 } = this.state;
    // TODO: Implement your logic how you decide 
    if (isP1 && isP2) {
      // CODE FOR PROMPTING WHICH DASHBOARD TO GO
      return;
    }
    if (isP1) return history.push('/p1dashboard');
    if (isP2) return history.push('/p2dashboard');
    return history.push('/configpage');
  }
}

如果这不起作用,至少看看代码结构。有些地方不需要使用
else
语句。使用
setState
的函数版本。利用对象/数组解构。您可能还应该阅读JS世界中基于
!!response&&response.length?true:false;
行–或者我在这里遗漏了什么。

您需要传递一个对象来获取。您所拥有的应该是语法错误。它应该是fetch({url:…,})。请注意括号前提似乎是
fetch()如果服务器返回404,则
将抛出一个错误。好吧,它不返回。@Malvolio问题与fetch无关。我刚刚给出了一个整体函数。fetch工作正常。已更新问题
设置状态
是(通常)异步。在react组件中,您将对
渲染
。此时,您可以确定
此.state
已更新。此处有一些错误。例如,
setDashboard()
声明为
async
,因此它总是自动返回一个承诺。您在承诺中额外包装它是完全不必要的,并且被认为是反模式的。对于
fetchUserAccounts()
,这一回答大部分都是错误的。@jfriend00它返回一个承诺,就像我写的一样,但因为没有“返回"语句它会自动解析承诺,而您无法控制它何时会解析。如果
fetchUserAccounts
有返回,但只有部分返回,因此同样的情况也会发生。这也是有意义的,因为它会将他重定向到配置页面,就好像在到达
fetchUserAccounts之前,状态中没有更新配置文件类型一样。如果您的异步函数既不返回承诺,也不返回任何内容-它将立即得到解决,因为
await
无需等待任何内容。As
async
函数将在函数中的所有
await
语句完成后解决它的承诺,然后在函数完成时重新执行在最后一个
wait
之后执行代码。由于没有
return
语句,承诺的解析值将是
未定义的
,但承诺仍然会在适当的时间正确解析。我并不是说OP的代码是完美的,但您对需要执行的操作的描述是错误的。您不知道ed从
异步
函数手动返回承诺。