问题描述
我的reactjs中的axios.post调用出现同步问题。 我有一个输入区域,供用户选择要提交到axios.post的本地文件,该文件被转换为arraybuffer,然后通过axios调用发送给Microsoft Faces api。如果选择图像,则按分析按钮,同步将关闭,并尝试在没有数组缓冲区的情况下发出发布请求。如果我第二次单击它,它将正确显示该帖子。
我对等待和异步还很陌生,对我的问题的任何投入都会有很大的帮助。我曾考虑过使用布尔值标志,但想学习如何通过正确的设计更好地实现此功能。
import React,{ useState } from "react";
import axios from "axios";
import { Button,Container,Row,Col } from "react-bootstrap";
import "../../styling/FacialRecognition.css";
import defaultimage from "../../assets/images/defaultimage.png";
function FacialRecognition() {
const [image,setimage] = useState("");
const [imageData,setimageData] = useState([]);
const [responseData,setResponseData] = useState([]);
const [dataLoad,setDataLoad] = useState(false);
//translates the local file to the array buffer,and sets the imageData.
function TranslateImagetoArrayBuffer(imagetoTranslate) {
let reader = new FileReader();
reader.readAsArrayBuffer(imagetoTranslate);
reader.onloadend = () => {
setimageData(reader.result);
};
}
//Makes the call with the url,options,and the arraybuffer.
function ProcessImage(localImage) {
TranslateImageArrayBuffer(localImage);
console.log("ImageData: " + imageData);
var subscriptionKey = "<subscriptionkey>";
var uriBase =
"https://(urlgoeshere).cognitiveservices.azure.com/face/v1.0/detect";
const options = [
"returnFaceId=true","returnFaceLandmarks=true","returnFaceAttributes=age,gender,headPose,smile,facialHair,glasses,emotion,hair,makeup,accessories",];
uriBase = uriBase.concat("?",options.join("&"));
// Perform the REST API call.
axios
.post(uriBase,imageData,{
headers: {
"Content-Type": "application/octet-stream","Ocp-Apim-Subscription-Key": subscriptionKey,},})
.then(function (response) {
// display the image.
var blob = new Blob([imageData]);
var url = URL.createObjectURL(blob);
setDataLoad(true);
document.querySelector("#sourceImage").src = url;
console.log("Status text: " + response.status);
console.log("Status text: " + response.statusText);
console.log(response.data);
setResponseData(response.data);
})
.catch(function (error) {
console.log(error);
});
}
let value = responseData.map((e) => JSON.stringify(e,null,2));
return (
<div>
<Container fluid="xl">
<Row>
<Col xs="auto">
<p>
Select a local image,and then click the <b>Analyze face button.</b>
</p>
</Col>
</Row>
<Row>
<Col x="auto">
<label>Image to analyze: </label>
<input
type="file"
name="inputimage"
id="inputimage"
autoComplete="off"
accept="image/png,image/jpeg"
onChange={(e) => setimage(e.target.files[0])}
style={{ width: "60%",marginLeft: "1vw" }}
/>
<Button
variant="info"
onClick={() => ProcessImage(image)}>
Analyze face
</Button>
</Col>
</Row>
<Row style={{ marginTop: "2vw" }}>
<Col xs="6">
<label>
<strong>Response</strong>
</label>
</Col>
<Col xs="auto">
<label>
<strong>Source Image</strong>
</label>
</Col>
</Row>
<Row>
<Col>
{dataLoad ? (
<textarea
id="responseTextArea"
className="UIInput"
style={{ width: "100%",height: "429px" }}
value={value}
readOnly={true}
disabled="disabled"></textarea>
) : (
<textarea
id="responseTextArea"
className="UIInput"
style={
dataLoad
? { display: "none" }
: { width: "100%",height: "auto" }
}
defaultValue="This field will display analyzed data on the image"
readOnly={true}
disabled="disabled"></textarea>
)}
</Col>
<Col xs="6">
{dataLoad ? (
<img
id="sourceImage"
alt=""
style={
dataLoad
? { width: "80%" }
: { display: "none" }
}
/>
) : (
<img
id="defaultimage"
src={defaultimage}
alt=""
style={
dataLoad
? { display: "none" }
: { width: "80%" }
}
/>
)}
</Col>
</Row>
</Container>
</div>
);
}
export default FacialRecognition;
我还尝试将TranslateImagetoArrayBuffer
设置为异步函数,并将axios调用置于.then(response => {axios.post...})
内,但不走运。
编辑:我也尝试过将我的Translate函数内容包装在一个Promise中。
async function TranslateImagetoArrayBuffer(imagetoTranslate) {
return new Promise((resolve,reject) => {
var reader = new FileReader();
reader.onload = () => {
setimageData(reader.result);
resolve(imageData);
};
reader.onerror = () => {
reject(reader.result);
};
reader.readAsArrayBuffer(imagetoTranslate);
});
}
,并在我的ProcessImage函数中使用const contents = await TranslateImagetoArrayBuffer(localImage);
行以等待该值。仍然有同步问题。
解决方法
我无法使其与异步一起工作,所以我将函数onChange移到了用于输入文件的位置,以将图像转换为数组缓冲区,而不是在ProcessImage()
中进行调用。
<input
type="file"
name="inputImage"
id="inputImage"
autoComplete="off"
accept="image/png,image/jpeg"
onChange={(e) =>{ TranslateImageToArrayBuffer(e.target.files[0]);setImage(e.target.files[0]) }}
style={{ width: "60%",marginLeft: "1vw" }}
/>
<Button
variant="info"
onClick={() => ProcessImage()}>
Analyze face
</Button>
这避免了进行异步设置的需要。