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

时间:2020-08-12 16:23:49

标签: javascript node.js promise apollo

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

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

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

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

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

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

哪种Javascript模式使之成为可能?

1 个答案:

答案 0 :(得分:3)

他们将使用状态变量,状态变量以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>