javascript - react native : synchronously run functions

标签 javascript reactjs react-native es6-promise

我是 OOP 的新手。我对 promise /异步/同步运行函数的了解很简单。非常感谢您的时间和关注!

这是来自 React-Native 文档的示例:

async function getMoviesFromApi() {
    try {
      let response = await fetch('https://facebook.github.io/react-native/movies.json');
      let responseJson = await response.json();
      return responseJson.movies;
    } catch(error) {
      console.error(error);
    }
  }

正如我从上面的代码中了解到的,getMoviesFromApi 被声明为异步函数。这意味着它将一个接一个地执行功能。正确的?不对请指正!

它会先等待 fetch 完成然后调用 response.json,对吗?

我有几个函数,它们通过 fetch 从服务器获取数据,然后将它们插入到 sqlite 数据库中。所以他们不会返回任何东西。

在上面的例子中,fetch 返回了一些东西。但我的职能,不是。那么,我可以使用这个结构让 javascript 运行我的函数吗?实现此目标的最佳实践/正确解决方案是什么?

let query = [];
export default class Main extends Component(){
  constructor(props){
    super(props);
  }
  
  componentWillMount(){
    this.getBookable();
    this.getBooked();
    this.runQuery();
    this.redirectUser();
    //// i need this functions to run consequently. not all in same time, one after eachother
  }
  
  getBookable(){
    let fetchedData = fetch(); /// Fetchs data from remote server
    query.push('INSERT INTO bookable (data) VALUES (' + fetchedData + ')');
  }
  
  getBooked(){
    let fetchedData = fetch(); /// Fetchs data from remote server
    query.push('INSERT INTO booked (data) VALUES (' + fetchedData + ')');
  }
  
  runQuery(){
    for(let i=0; i < query.length; i++){
      db.transaction((tx) => {
        tx.executeSql(query[i],[], (tx, results) => {
            console.log('Query', query[f], 'Executed. results:', results);
        }, (err)=>{
            console.log('Something went wrong while executing query',query[i],'error is', err);
          });
      });
    }
  }
  
  redirectUser(){
    Actions.tabbar({type: 'reset'});
    //// Using redux. redirect user to another page
  }
  
}
首先,我得到可预订的类(class),然后预订类(class),将它们插入数据库,然后通过 redux 将用户重定向到另一个页面 我应该如何更新我的代码?


更新:

根据@Bergi 更新代码: 这是正确的方法吗?

import React, {Component, PropTypes} from 'react';
import {
  ActivityIndicator,
  StyleSheet,
  Text,
  View,
  NetInfo,
  AlertIOS,
} from 'react-native';

var SQLite = require('react-native-sqlite-storage');
var Loading = require("./Loading");
var DeviceInfo = require('react-native-device-info');
import { Actions } from 'react-native-router-flux';
var LOADING = {};
var db = SQLite.openDatabase({name : "oc.db", location: 'default'});
import CodePush from "react-native-code-push";
import I18n from 'react-native-i18n';
import translations from './translations';
I18n.fallbacks = true;

export default class Grab extends Component{
  constructor(props) {
        super(props);
        this.state = {
            terms: '',
            isLoading: false,
            isConnected: null,
            coursesFetched: false,
            registerFetched: false,
        };
    }

  componentWillMount() {

    NetInfo.isConnected.fetch().then(isConnected => {
      this.setState({
        isConnected: isConnected
      });
    });

    NetInfo.isConnected.addEventListener(
      'change',
      isConnected => {
        this.setState({
          isConnected: isConnected
        });
        console.log('Grab: internet status is', this.state.isConnected);
        this.sync();
      }
    );

    this.GrabData();

  }

  toggleAllowRestart() {
    this.state.restartAllowed
      ? CodePush.disallowRestart()
      : CodePush.allowRestart();

    this.setState({ restartAllowed: !this.state.restartAllowed });
  }

  sync() {
    console.log("Grab: Running manual code push update");
  CodePush.sync(
    {
      installMode: CodePush.InstallMode.IMMEDIATE,
      updateDialog: false
    },
  );
}

  async getUsers(){
    let userlist = [];
    let query = ["SELECT * FROM users"];
    await db.transaction(tx => {
      return Promise.all(query.map(async (q) => {
        try {
          let results = await tx.executeSql(q, []);
          console.log('Query', q, 'Executed. results:', results);
          for(let ind = 0; ind < len; ind++ ){
            userlist[ind] = {
              userId: results.rows.item(ind).userId,
              userName: results.rows.item(ind).userName,
              userMail: results.rows.item(ind).userMail,
              active: results.rows.item(ind).active,
              firstName: results.rows.item(ind).firstName,
              lastName: results.rows.item(ind).lastName,
              accessToken: results.rows.item(ind).access_token,
              host: results.rows.item(ind).host,
            };
          }
        } catch(err) {
          console.log('Something went wrong while executing query', q, 'error is', err);
        }
      }));
    });
    return userlist;
  }

  async getBookable(users){
    let results = [];
    for(let n=0; n < users.length; n++){
      try {
        let host = users[n].host;
        let access_token = users[n].access_token;
        let userId = users[n].userId;
        let response = await fetch(host + 'event/my_events', {
          method: 'POST',
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            'language': DeviceInfo.getDeviceLocale(),
            'Authorization': 'Bearer ' + access_token
          }
        });
        let responseData = await response.json();
        //// Get container details
        if(responseData.container.length > 0){
          for(let i=0; i < responseData.container.length; i++){
            let cnid = responseData.container[i].nid;
            let ctitle = responseData.container[i].title;
            results.push(
              "INSERT INTO containersC (userId, nid, title) VALUES ('" + userId + "','" + cnid + "', '" + ctitle + "')"
            );
            //// Get courses for each container
            for(let j=0; j < responseData.container[i].course.length; j++){
              let course_id = responseData.container[i].course[j].nid;
              let title = responseData.container[i].course[j].title;
              let cost = responseData.container[i].course[j].cost;
              let status = responseData.container[i].course[j].status;
              let period = responseData.container[i].course[j].period.time_sys;
              //// Get details for each course
              try {
                let resp = await fetch(host + 'event/course_detail/' + course_id, {
                  method: 'POST',
                  headers: {
                    'Accept': 'application/json',
                    'Content-Type': 'application/json',
                    'language': DeviceInfo.getDeviceLocale(),
                    'Authorization': 'Bearer ' + access_token
                  }
                });
                let respData = await resp.json();

                let desc = respData.data.content[0].value;
                let capacity = respData.data.content[1].value;
                let image = respData.data.image;
                let status = respData.data.book;
                let cancel = respData.data.cancel;
                let cd = responseData.data.dates;

                results.push(
                  "INSERT INTO courses (userId, course_id, container_nid, title, cost, status, period, desc, capacity, image, cancel) VALUES ('" + userId + "','" + course_id + "', '" + cnid + "', '" + title + "', '" + cost + "', '" + status + "', '" + period + "', '" + desc + "', '" + capacity + "', '" + image + "', '" + cancel + "')"
                );

                //// Getting lecture dates for each course
                for(let a=0; a < cd.length; a++){
                  let sdate = cd[a].start_time.split(" ");
                  let edate = cd[a].end_time.split(" ");
                  results.push(
                    "INSERT INTO lectures (userId, course_id, title, start_time, end_time, start_date, end_date, room, teacher) VALUES ('" + userId + "','" + course_id + "', '" + cd[a].title + "', '" + sdate[1] + "', '" + edate[1] + "', '" + sdate[0] + "', '" + edate[0] + "', '" + cd[a].room + "', '" + cd[a].teacher + "')"
                  );
                }
                //// End getting lecture dates for courses
                return true;
              } catch(error) {
                console.error(error);
              }
              //// End getting details for courses
            }
            //// End getting courses for containers
          }
        }
        //// End getting container details
        return true;
      } catch(error) {
        console.error(error);
      }
    }
  }

  redirectUser(){
    Actions.tabbar({type: 'reset'});
  }

  async runQuery(query) {
    await db.transaction(tx => {
      return Promise.all(query.map(async (q) => {
        try {
          let results = await tx.executeSql(q, []);
          console.log('Query', q, 'Executed. results:', results);
        } catch(err) {
          console.log('Something went wrong while executing query', q, 'error is', err);
        }
      }));
    });
    return true;

  }

  async function GrabData(){
    try {
      let users = await getUsers();
      //let [courses, register, evaluation] = await Promise.all([getCourses(users), getRegister(users), getEvaluation(users)]);
      let [courses] = await Promise.all([getCourses(users)]);
      //let query = [courses, register, evaluation];
      let query = [courses];
      await runQuery(["DELETE FROM containersC", "DELETE FROM courses", "DELETE FROM lectures", "DELETE FROM containersR", "DELETE FROM register", "DELETE FROM lectures", "DELETE FROM evaluations", "DELETE FROM fields"]);
      await runQuery(query);
      this.redirectUser();
    } catch(error){
      console.log(error);
    }
  }


  render() {

return(
    <View style={styles.container}><Loading/></View>
  );
  }

}

var styles = StyleSheet.create({
    container: {
      flex: 1,
      backgroundColor: "#fff",
      flexDirection: "column",
    },
});

Grab = CodePush(Grab);

我正在使用 react-native-sqlite-storage : https://github.com/andpor/react-native-sqlite-storage

最佳答案

getMoviesFromApi is declared as async function. which means it will execute functions one after other.

没有。这仅意味着它会在调用时返回一个 promise ,并且您可以在函数体中使用 await 运算符。

it will first wait for fetch to finish then call response.json, right?

是的,因为它使用 await 来停止对方法的评估,直到 promise 解决。

I have few functions, which get data from a server via fetch, then insert them to sqlite database. so they don't return anything.

他们应该返回 promise - 即使他们是白白 promise ,他们仍然可以等待。

但在您的情况下,他们实际上应该返回一些东西。您的全局静态 query 数组是一个可怕的反模式。不是用查询填充它,每个方法应该返回(一个 promise )一个查询,然后可以在每个实例和每个调用的基础上将其传递给执行程序。只有这样,使用事务才真正开始有意义。

您的代码应如下所示:

class Main extends Component() {
  …
  async getBookable(){
    var response = await lfetch(host, {
      method: 'POST',
      headers: …
    });
    var responseData = await response.json();
    return 'INSERT INTO bookable (data) VALUES (' + responseData + ')'); // beware of SQL injections!!!
  }

  getBooked(){
    // the very same - here written without async/await:
    return fetch(host, {
//  ^^^^^^ important - return a promise
      method: 'POST',
      headers: …
    })
    .then(response => response.json())
    .then(responseData => {
      return 'INSERT INTO booked (data) VALUES (' + responseData + ')';
    });
    // don't `catch` anything, don't call `done` - just return the promise chain
    // errors will be handled in the try/catch below
  }

  async runQuery(query) {
    await db.transaction(tx => {
      return Promise.all(query.map(async (q) => {
        try {
          let results = await tx.executeSql(q, []);
          console.log('Query', q, 'Executed. results:', results);
        } catch(err) {
          console.log('Something went wrong while executing query', q, 'error is', err);
        }
      }));
    });
    return true;
  }

  async function getStore() {
    try {
      // actually you can fetch these in parallel, right?
      let [bookable, booked] = await Promise.all([getBookable(), getBooked()]);
      let query = [bookable, booked];
      await runQuery(query);
      redirectUser();
    } catch(error) {
      console.error(error);
    }
  }
}

关于javascript - react native : synchronously run functions,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39959700/

相关文章:

reactjs - 如何配置 Nginx 服务器以与子文件夹中的 React 应用程序配合使用?

javascript - 我需要从不同的函数调用 ClearInterval

javascript - 如何以及为什么在代码中使用 SUPER?

javascript - jQuery Ajax 两个相同的函数适用于其中一个而不适用于另一个

javascript - req.session.cart [object object] [object object] 如何在我的 sapper/svelte 应用程序中迭代和查看它

javascript - 带有方形单元格的可调整大小的表格

javascript - React-Router:添加登陆页面

javascript - 如何在几秒钟后卸载或删除 React 组件?

javascript - React Native 和 Firebase 实时数据库

android - 失败 [INSTALL_PARSE_FAILED_NO_CERTIFICATES] React native