Javascript承诺:返回“进行中”响应,直到承诺解决?

问题描述

这并不是一个真正的Apollo问题,它是一个Javascript Promise问题,但是使用了Apollo的示例,因为那是我唯一一次看到它。

Apollo有一个类似this的React钩子:

const { loading,error,data } = useQuery(GET_DOGS);

我了解它如何返回error -如果承诺解析器抛出错误,则会返回错误

我了解它如何返回data -当承诺解析器完成时,它将返回数据。

但是它如何返回loading,然后又返回data?我已经编码了许多node.js承诺解析器,还没有看到一种模式,该模式可以在操作进行中返回loading,然后再返回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,data};
}

function Example() {
    const {loading,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>