开发者问题收集

在 JavaScript 中异步函数之后运行函数

2019-06-11
7942

我正在尝试编写一个运行异步函数的代码,当它完成后,它会运行另一段代码。

我尝试将异步函数放在承诺中(如下面的代码所示)并使用 then 方法,但没有成功。

函数内部发生的事情并不重要,但我还是把它包括在内,以防我弄错了,而它确实发生了......

getData = async(file) =>{
        let data = await fetch(file);
        data = await data.text();
        return(data);
    }

    getDataAndUsername = async() => {
        this.setState({data: JSON.parse(await this.getData("/getData"))});
        this.setState({username: await this.getData("/user")});
        console.log('done');
    }

getDataAndUsername 是我尝试在其他函数之前运行的异步函数。

CheckInDataBase = (username) => {
        console.log('checking In DataBase');
        this.state.data.forEach((element)=>{
            if(element.username === username){
                    this.setState({exist: true});
                }
            });
            if (!(this.state.exist)){
            axios.post('/createUser', {"username": username, "status": "Working"});
            this.setState({exist: true});
        }
        }

这是我尝试在异步函数之后运行的常规函数​​

这是代码:

new Promise((res) => {
            this.getDataAndUsername();
            res();
        }).then(
            this.CheckInDataBase(this.state.username)
        )

现在发生的事情是,this.CheckInDatabase 在 getDataAndUsername 完成之前运行。

3个回答

由于被定义为 async ,您的 getDataAndUsername 已经是一个 Promise,因此无需将其包装在 new Promise() 中。您只需执行以下操作:

this.getDataAndUsername().then( _ => {
  this.CheckInDataBase(this.state.username);
})

它应该可以工作。

为什么您的代码一开始就不起作用

您正在用这个创建一个新的承诺:

new Promise((res) => {
            this.getDataAndUsername();
            res();
        }) ...

在那里,您正在调用 this.getDataAndUsername() ,但忽略了它是否解析。该代码将立即调用 res ,因此在 getDataAndUsername 解析之前调用了 checkInDatabase

您可以等待 getDataAndUsername 解析:

new Promise((res) => {
            return this.getDataAndUsername().then(_ => {res()})
        }) ...

重点是使用 then 等待承诺解析,同时添加 return

但是,如上所述,没有必要这样做,因为 getDataAndUsername 已经是一个 Promise。

Sergeon
2019-06-11

正如我在评论中所写,您更新状态的频率太高了。这是一个异步过程,因此您可能最终会检查或循环遍历旧状态。

我建议您尽可能少地使用 this.setState ,而是在尽可能多的函数中返回值。这样,您就可以拆分功能,而不依赖于 React 的状态。

这是我对您的问题的建议:

class App extends React.PureComponent {
  getData = async (file) =>{
    let data = await fetch(file);
    return await data.text();
  };

  getDataAndUsername = async () => ({
    data: JSON.parse(await this.getData("/getData")),
    username: JSON.parse(await this.getData("/user"))
  });

  checkInDataBase = ({ username, data }) => {
    console.log('checking In DataBase');
    return !!data.find(element => element.username === username);
  };

  addUser = async username => await axios.post('/createUser', {"username": username, "status": "Working"});

  myCheckFunction = async () => {
    const dataAndUsername = await this.getDataAndUsername();
    if (dataAndUsername) {
      if (!this.checkInDataBase(dataAndUsername)) {
        const newUser = await this.addUser(dataAndUsername.username);
        dataAndUsername.data.push(newUser);
      }
      // A single place where you update the state
      this.setState({
        ...dataAndUsername,
        exists: true
      })
    }
  }
}
Radu Nemerenco
2019-06-11

尝试:

this.getDataAndUsername().then((response) => {
  /**
   * Your code that you want to run after getDataAndUsername
   */
}, (error) => {
  /**
   * Handle error here
   */
});

或者使用 async/await

(async function() {
  try {
    const dataAndUsername = await this.getDataAndUsername();
    /**
     * Your code that you want to run after getDataAndUsername
     */

  } catch(e) {
    /**
   * Handle error here
   */
  }
})();
Easwar
2019-06-11