Javascript 承诺:Return 'In Progress' 响应直到承诺解决?
Javascript Promise: Return 'In Progress' Response Until Promise Resolves?
这不是真正的 Apollo 问题,它是一个 Javascript promises 问题,但使用了 Apollo 的示例,因为那是我记得唯一一次看到它。
Apollo 有一个 React 钩子,看起来像 this:
const { loading, error, data } = useQuery(GET_DOGS);
我明白它是如何 returns error
-- 如果承诺解析器抛出错误,你会得到一个错误。
我了解它是如何 returns data
-- 当承诺解析器完成时,它 returns 数据。
但是如何 return loading
然后 return data
?我已经编写了很多 node.js promise 解析器,但还没有看到一个模式可以 return loading
在操作过程中,然后 return data
.
什么 Javascript 模式使这成为可能?
他们会使用一个从 true
开始并在完成后切换到 false
的状态变量,大概是这样的:
function useQuery(/*...*/) {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [data, setData] = useState(null);
useEffect(() => {
let cancelled = false;
goGetTheStuff()
.then(data => {
if (!cancelled) {
setData(data);
setLoading(false);
}
})
.catch(error => {
if (!cancelled) {
setError(error);
setLoading(false);
}
});
return () => {
cancelled = true;
};
}, []);
return {loading, error, data};
}
实例:
const {useState, useEffect} = React;
function goGetTheStuff() {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.7) {
// Emulate success
resolve({data: "here"});
} else {
// Emulate failure
reject(new Error("Couldn't get the data"));
}
}, 800);
});
}
function useQuery(/*...*/) {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [data, setData] = useState(null);
useEffect(() => {
let cancelled = false;
goGetTheStuff()
.then(data => {
if (!cancelled) {
setData(data);
setLoading(false);
}
})
.catch(error => {
if (!cancelled) {
setError(error);
setLoading(false);
}
});
return () => {
cancelled = true;
};
}, []);
return {loading, error, data};
}
function Example() {
const {loading, error, data} = useQuery();
return (
<div>
<div>loading: {JSON.stringify(loading)}</div>
<div>data: {data && JSON.stringify(data)}</div>
<div>error: {error && error.message}</div>
</div>
);
}
ReactDOM.render(<Example/>, document.getElementById("root"));
<div>70% of the time when you run this, the async operation succeeds; 30% of the time, it fails. Run repeatedly if you want to see both scenarios.</div>
<hr>
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>
这不是真正的 Apollo 问题,它是一个 Javascript promises 问题,但使用了 Apollo 的示例,因为那是我记得唯一一次看到它。
Apollo 有一个 React 钩子,看起来像 this:
const { loading, error, data } = useQuery(GET_DOGS);
我明白它是如何 returns error
-- 如果承诺解析器抛出错误,你会得到一个错误。
我了解它是如何 returns data
-- 当承诺解析器完成时,它 returns 数据。
但是如何 return loading
然后 return data
?我已经编写了很多 node.js promise 解析器,但还没有看到一个模式可以 return loading
在操作过程中,然后 return data
.
什么 Javascript 模式使这成为可能?
他们会使用一个从 true
开始并在完成后切换到 false
的状态变量,大概是这样的:
function useQuery(/*...*/) {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [data, setData] = useState(null);
useEffect(() => {
let cancelled = false;
goGetTheStuff()
.then(data => {
if (!cancelled) {
setData(data);
setLoading(false);
}
})
.catch(error => {
if (!cancelled) {
setError(error);
setLoading(false);
}
});
return () => {
cancelled = true;
};
}, []);
return {loading, error, data};
}
实例:
const {useState, useEffect} = React;
function goGetTheStuff() {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() < 0.7) {
// Emulate success
resolve({data: "here"});
} else {
// Emulate failure
reject(new Error("Couldn't get the data"));
}
}, 800);
});
}
function useQuery(/*...*/) {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [data, setData] = useState(null);
useEffect(() => {
let cancelled = false;
goGetTheStuff()
.then(data => {
if (!cancelled) {
setData(data);
setLoading(false);
}
})
.catch(error => {
if (!cancelled) {
setError(error);
setLoading(false);
}
});
return () => {
cancelled = true;
};
}, []);
return {loading, error, data};
}
function Example() {
const {loading, error, data} = useQuery();
return (
<div>
<div>loading: {JSON.stringify(loading)}</div>
<div>data: {data && JSON.stringify(data)}</div>
<div>error: {error && error.message}</div>
</div>
);
}
ReactDOM.render(<Example/>, document.getElementById("root"));
<div>70% of the time when you run this, the async operation succeeds; 30% of the time, it fails. Run repeatedly if you want to see both scenarios.</div>
<hr>
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>