如何使 Javascript/React/Typescript 获取调用异步?
How to make a Javascript/React/Typescript fetch call asynchronous?
考虑以下 Javascript/React 代码:
// Javascript function that has a fetch call in it.
export const signIn = (email:string, password:string) => {
console.log("FETCHING...");
fetch(`${endPoint}/sign_in`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email,
password
})
})
.then((response) => {
return response.json()
})
.then(({ data }) => {
console.log("FETCHED DATA...")
})
.catch((error) => {
console.error('ERROR: ', error)
})
console.log("DONE FETCHING...");
}
// A functional component that references signIn.
export const SignIn: React.FC<Props> = () => {
// irrelevant code ...
const onSubmit = (e: CustomFormEvent) => {
e.preventDefault()
console.log("SIGNING IN...")
// calls my signIn function from above
// I don't want this to finish until the fetch inside it does.
signIn(email, password, setAuthentication, setCurrentUser)
console.log("SIGNED IN...");
}
return <>A form here submits and calls onSubmit</>
}
这会产生以下控制台日志输出:
SIGNING IN...
FETCHING...
DONE FETCHING...
SIGNED IN...
FETCHED DATA...
我希望 FETCHED DATA...
在 DONE FETCHING...
之前出现。我试过玩弄 aysnc/await
但那不起作用所以我不知道从这里去哪里。
再加一个.then
.then((response) => {
return response.json()
})
.then(({ data }) => {
console.log("FETCHED DATA...")
return
}).then(()=> {
console.log("DONE FETCHING...");
})
.catch((error) => {
console.error('ERROR: ', error)
})
如果您希望 console.log
等到 promise 得到解决,它必须在 then
语句中。这是一个使用 async/await
:
的示例
export const signIn = async (email:string, password:string) => {
console.log("FETCHING...");
const response = await fetch(`${endPoint}/sign_in`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email,
password
})
})
const data = await response.json();
console.log("FETCHED DATA...")
console.log("DONE FETCHING...");
}
如果您希望 console.log 在数据获取完成后发生,您还需要将其转换为 async
函数:
const onSubmit = async (e: CustomFormEvent) => {
e.preventDefault()
console.log("SIGNING IN...")
// calls my signIn function from above
// I don't want this to finish until the fetch inside it does.
await signIn(email, password, setAuthentication, setCurrentUser)
console.log("SIGNED IN...");
}
为了使用 async await,您需要 return 来自调用的承诺。所以基本上你不执行 .then
并将调用包装在 try catch 块中。
export const signIn = async (email:string, password:string) => {
console.log("FETCHING...");
return fetch(`${endPoint}/sign_in`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email,
password
})
})
}
和
const onSubmit = async (e: CustomFormEvent) => {
e.preventDefault()
console.log("SIGNING IN...")
// calls my signIn function from above
// I don't want this to finish until the fetch inside it does.
try {
const data = await signIn(email, password, setAuthentication, setCurrentUser)
// Parse data, do something with it.
console.log("SIGNED IN...");
} catch (e) {
// handle exception
}
}
您可能想更多地了解 JavaScript 中的 promise 是如何工作的。
signIn
中有一个问题。你现在正在做的是:
function signIn() {
// 1. log FETCHING
// 2. call asynchronous fetch function
// 3. log DONE FETCHING
}
这里的关键是fetch
是异步的。该程序不会等到它完成后再继续。看到问题了吗? JavaScript 解释器将进入 运行 第 3 步,而不等待第 2 步完成。
有多种方法可以解决这个问题。首先,您可以使用 then
。这是一个例子:
promise
.then(res => func1(res))
.then(res => func2(res))
.then(res => func3(res))
在这里,你告诉 JavaScript 到:
- 运行
promise
,等待解决.
- 从
promise
中取出结果并将其传递给func1
。等待 func1
解决。
- 从
func1
中取出结果并将其传递给func2
。等待 func2
解决。
- 等等
这里的主要区别在于,您 运行 按顺序排列每个 then
块,等待每个先前的承诺得到解决,然后再转到下一个。 (而在您没有等待 promise 解决之前)。
你的 promise 代码看起来像:
export const signIn = (email: string, password: string) => {
console.log("FETCHING...")
// Note that we return the promise here. You will need this to get onSubmit working.
return fetch(/* args */)
.then(res => res.json())
.then(({ data }) => console.log("DONE FETCHING"))
.catch(err => /* HANDLE ERROR */)
}
解决此问题的第二种方法是使用 async
和 await
。 async
和 await
只是 promises 的语法糖。它在下面所做的是完全相同的,因此请确保您首先了解 promises 是如何工作的。这是带有 async
和 await
的代码:
// The async keyword here is important (you need it for await)
export const signIn = async (email: string, password: string) => {
console.log("FETCHING...");
try {
const res = await fetch(/* args */) // WAIT for fetch to finish
const { data } = res.json()
console.log("FETCHED DATA...")
} catch (err) {
/* HANDLE ERROR */
}
console.log("DONE FETCHING...")
}
onSubmit
中还有第二个类似的问题。这个想法是一样的;我会让你自己想办法(重要的是你必须 return 来自 signIn
的 Promise
)。
考虑以下 Javascript/React 代码:
// Javascript function that has a fetch call in it.
export const signIn = (email:string, password:string) => {
console.log("FETCHING...");
fetch(`${endPoint}/sign_in`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email,
password
})
})
.then((response) => {
return response.json()
})
.then(({ data }) => {
console.log("FETCHED DATA...")
})
.catch((error) => {
console.error('ERROR: ', error)
})
console.log("DONE FETCHING...");
}
// A functional component that references signIn.
export const SignIn: React.FC<Props> = () => {
// irrelevant code ...
const onSubmit = (e: CustomFormEvent) => {
e.preventDefault()
console.log("SIGNING IN...")
// calls my signIn function from above
// I don't want this to finish until the fetch inside it does.
signIn(email, password, setAuthentication, setCurrentUser)
console.log("SIGNED IN...");
}
return <>A form here submits and calls onSubmit</>
}
这会产生以下控制台日志输出:
SIGNING IN...
FETCHING...
DONE FETCHING...
SIGNED IN...
FETCHED DATA...
我希望 FETCHED DATA...
在 DONE FETCHING...
之前出现。我试过玩弄 aysnc/await
但那不起作用所以我不知道从这里去哪里。
再加一个.then
.then((response) => {
return response.json()
})
.then(({ data }) => {
console.log("FETCHED DATA...")
return
}).then(()=> {
console.log("DONE FETCHING...");
})
.catch((error) => {
console.error('ERROR: ', error)
})
如果您希望 console.log
等到 promise 得到解决,它必须在 then
语句中。这是一个使用 async/await
:
export const signIn = async (email:string, password:string) => {
console.log("FETCHING...");
const response = await fetch(`${endPoint}/sign_in`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email,
password
})
})
const data = await response.json();
console.log("FETCHED DATA...")
console.log("DONE FETCHING...");
}
如果您希望 console.log 在数据获取完成后发生,您还需要将其转换为 async
函数:
const onSubmit = async (e: CustomFormEvent) => {
e.preventDefault()
console.log("SIGNING IN...")
// calls my signIn function from above
// I don't want this to finish until the fetch inside it does.
await signIn(email, password, setAuthentication, setCurrentUser)
console.log("SIGNED IN...");
}
为了使用 async await,您需要 return 来自调用的承诺。所以基本上你不执行 .then
并将调用包装在 try catch 块中。
export const signIn = async (email:string, password:string) => {
console.log("FETCHING...");
return fetch(`${endPoint}/sign_in`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email,
password
})
})
}
和
const onSubmit = async (e: CustomFormEvent) => {
e.preventDefault()
console.log("SIGNING IN...")
// calls my signIn function from above
// I don't want this to finish until the fetch inside it does.
try {
const data = await signIn(email, password, setAuthentication, setCurrentUser)
// Parse data, do something with it.
console.log("SIGNED IN...");
} catch (e) {
// handle exception
}
}
您可能想更多地了解 JavaScript 中的 promise 是如何工作的。
signIn
中有一个问题。你现在正在做的是:
function signIn() {
// 1. log FETCHING
// 2. call asynchronous fetch function
// 3. log DONE FETCHING
}
这里的关键是fetch
是异步的。该程序不会等到它完成后再继续。看到问题了吗? JavaScript 解释器将进入 运行 第 3 步,而不等待第 2 步完成。
有多种方法可以解决这个问题。首先,您可以使用 then
。这是一个例子:
promise
.then(res => func1(res))
.then(res => func2(res))
.then(res => func3(res))
在这里,你告诉 JavaScript 到:
- 运行
promise
,等待解决. - 从
promise
中取出结果并将其传递给func1
。等待func1
解决。 - 从
func1
中取出结果并将其传递给func2
。等待func2
解决。 - 等等
这里的主要区别在于,您 运行 按顺序排列每个 then
块,等待每个先前的承诺得到解决,然后再转到下一个。 (而在您没有等待 promise 解决之前)。
你的 promise 代码看起来像:
export const signIn = (email: string, password: string) => {
console.log("FETCHING...")
// Note that we return the promise here. You will need this to get onSubmit working.
return fetch(/* args */)
.then(res => res.json())
.then(({ data }) => console.log("DONE FETCHING"))
.catch(err => /* HANDLE ERROR */)
}
解决此问题的第二种方法是使用 async
和 await
。 async
和 await
只是 promises 的语法糖。它在下面所做的是完全相同的,因此请确保您首先了解 promises 是如何工作的。这是带有 async
和 await
的代码:
// The async keyword here is important (you need it for await)
export const signIn = async (email: string, password: string) => {
console.log("FETCHING...");
try {
const res = await fetch(/* args */) // WAIT for fetch to finish
const { data } = res.json()
console.log("FETCHED DATA...")
} catch (err) {
/* HANDLE ERROR */
}
console.log("DONE FETCHING...")
}
onSubmit
中还有第二个类似的问题。这个想法是一样的;我会让你自己想办法(重要的是你必须 return 来自 signIn
的 Promise
)。