错误信息:
WARN Possible Unhandled Promise Rejection (id: 1):
Error: INVALID_STATE_ERR
send@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:31745:26
initialiseWebsocket@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:100544:21
loadUserData$@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:100610:40
tryCatch@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:7739:23
invoke@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:7912:32
tryCatch@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:7739:23
invoke@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:7812:30
http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:7822:21
tryCallOne@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:28596:16
http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:28697:27
_callTimer@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:29113:17
_callImmediatesPass@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:29152:17
callImmediates@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:29370:33
__callImmediates@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:3279:35
http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:3057:34
__guard@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:3262:15
flushedQueue@http://localhost:8081/index.bundle?platform=android&dev=true&minify=false&app=com.dcgymappfrontend&modulesOnly=false&runModule=true:3056:21
flushedQueue@[native code]
invokeCallbackAndReturnFlushedQueue@[native code]
被指责有问题的 useEffect:
React.useEffect(() => {
// Fetch the token from storage then navigate to our appropriate place
const loadUserData = async () => {
let userData;
try {
userData = await retrieveUserData();
} catch (e) {}
if(userData){
dispatch({ type: 'RESTORE_USER_DATA', userData: userData });
getChatData(userData, setChats, dispatch);
if(userData && !websocketInitialised){
console.log('web init called from *load user data*')
setWebsocketInitialised(true)
initialiseWebsocket(userData);
}
}
else{
dispatch({ type: 'RESTORE_USER_DATA_FAILED'});
}
};
loadUserData();
}, []);
initialliseWebsocket 函数
function initialiseWebsocket(userData){
console.log('sending websocket initialisation data.');
websocket.send(JSON.stringify({
'action': 'init',
'data' : {'token': userData.token}
}));
}
上面使用的 useState
const [websocketInitialised, setWebsocketInitialised] = React.useState(false);
async function getChatData(userData, setChats, dispatch){
console.log("fetching chat data");
// if we fail to download chat data, pull the old one from FS
const loadOldChatData = async () => {
let chats;
try {
chats = await retrieveChats();
} catch (e) {}
if(chats){
setChats(chats);
console.log("loaded cached chat data") ;
}
else{
setChats([]);
}
};
const onSuccess = (response) => {
if(response['chats']){
storeChats(response['chats']);
setChats(response['chats']);
console.log("chat data synced");
}
else{
loadOldChatData();
}
};
const onFailure = (response) => {
loadOldChatData();
};
fetch(Settings.siteUrl + '/messenger/get_chats/', {
method: "GET",
headers: {
"Content-type": "application/json; charset=UTF-8",
"Authorization": "Token " + userData.token
},
})
.then(response => response.json())
.then(response => {onSuccess(response)})
.catch(response => {onFailure(response)})
}
retrieveUseData() 很可能不是问题,因为这只是在我添加其他代码后才开始发生。
我是不是不应该使用这样的状态,还是应该使用处理函数的异步键?我试过了,但我仍然有同样的问题。您可以在第 4 行的错误中看到它提到了 'initialiseWebsocket' 函数。我猜这是路线原因。我认为解决方案将是它的一些异步版本......
答案 0 :(得分:2)
此错误告诉我们您没有或忘记处理异步代码中的错误。
我稍微修改了您的代码,如果您收到来自 console.log(error);
React.useEffect(() => {
// Fetch the token from storage then navigate to our appropriate place
(async () => {
try {
let userData = await retrieveUserData();
dispatch({ type: 'RESTORE_USER_DATA', userData });
await getChatData(userData, setChats, dispatch);
if (websocketInitialised) return;
console.log('web init called from *load user data*')
setWebsocketInitialised(true)
initialiseWebsocket(userData);
} catch (error) {
console.log(error);
dispatch({ type: 'RESTORE_USER_DATA_FAILED' });
}
})();
}, []);
你应该将 getChatData
重命名为 setChatData
,我也简化了这些代码......
async function getChatData(userData, setChats, _dispatch) {
try {
let response = await fetch(Settings.siteUrl + '/messenger/get_chats/', {
method: "GET",
headers: {
"Content-type": "application/json; charset=UTF-8",
"Authorization": "Token " + userData.token
},
}),
data = await response.json(),
chats = data['chats'];
if (!chats?.length) throw "empty chat data, pull the old one from FS";
storeChats(chats);
setChats(chats);
} catch (_) {
// if we fail to download chat data, pull the old one from FS
await retrieveChats()
.then(chats => setChats(chats))
.catch(() => setChats([]))
}
}
<块引用>
“我真的不明白你在用异步的东西做什么。”
async/await
只是 promise 的语法糖,它允许您以同步方式处理异步操作,async/await
await keyword
,您还需要一个 async
函数。async
关键字promise
让我们看一个例子:
let delay = (ms, msg, bool) => new Promise((res, rej) => setTimeout(!bool ? res : rej , ms,msg));
这个辅助函数为我们的例子创建了一个 promise
,它有 3 个参数,它把 millisecond
作为第一个参数,延迟,第二个是 message
作为有效负载。第三个是Boolean
;为真,则拒绝。
let delay = (ms, msg, bool) => new Promise((res, rej) => setTimeout(!bool ? res : rej, ms, msg));
let log = console.log;
async function myAsyncFn() {
let hello = await delay(100, "hello,");
let world = await delay(300, " world!");
// we use a symbol '@' to indicate that, its from `myAsyncFn`
log("@" , hello + world, "printed from async operation");
}
myAsyncFn();
log("As you can see that, this message print first");
// we are creating an async function and called immediately, In other to use `await keyword`
(async () => {
try {
let resolved = await delay(300,"resolved");
console.log(">" , `it ${resolved}!`);
// this will reject and catch via `try/catch` block;
let _ = await delay(600, "Error", true);
log("It will not print!");
// ...
} catch (error) {
log(">" , `we can catch "${error}" with try/catch, as like any sync code!`);
}
})()
如您所见,使用 async/await
时,它看起来好像一切都是同步的,对吗?甚至一切都是异步执行的!
您只需要使用 await
关键字使每个异步操作同步即可。