我是OOP的新手。我对promises /异步/同步运行函数的了解是基本的。我非常感谢你的时间和精力!
这是来自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
}
}
更新:
根据@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
答案 0 :(得分:4)
getMoviesFromApi
被声明为async function
。这意味着它会一个接一个地执行函数。
没有。这只意味着它会在调用时返回一个promise,并且你可以在函数体中使用await
运算符。
它会先等待fetch完成然后调用response.json,对吗?
是的,因为它使用await
来停止对方法的评估,直到诺言结算。
我的函数很少,它通过fetch从服务器获取数据,然后将它们插入到sqlite数据库中。所以他们不会退货。
他们应该回报承诺 - 即使他们没有承诺,他们仍然可以等待。
但是在你的情况下,他们实际上应该返回一些东西。你的全局静态query
数组是一个可怕的反模式。每个方法都应返回(一个承诺)查询,而不是用查询填充它,然后可以基于每个实例和每个调用将其传递给执行程序。只有这样,使用事务才真正开始有意义。
您的代码应如下所示:
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);
}
}
}