RubyLouvre/anu

View on GitHub
lib/createResource.js

Summary

Maintainability
B
4 hrs
Test Coverage
import { noop } from "../src/util";
import { createContext } from "../src/createContext";
const Empty = 0;
const Pending = 1;
const Resolved = 2;
const Rejected = 3;

export function createResource(loadResource, hash) {
    const resource = {
        read(cache, key) {
            if (hash === undefined) {
                return cache.read(resource, key, loadResource, key);
            }
            const hashedKey = hash(key);
            return cache.read(resource, hashedKey, loadResource, key);
        },
        preload(cache, key) {
            if (hash === undefined) {

                cache.preload(resource, key, loadResource, key);
                return;
            }
            const hashedKey = hash(key);
            cache.preload(resource, hashedKey, loadResource, key);
        },
    };
    return resource;
}

let CACHE_TYPE = 0xcac4e;


export function createCache(invalidator) {
    const resourceCache = new Map();

    function getRecord(resourceType, key) {
        let recordCache = resourceCache.get(resourceType);
        if (recordCache !== undefined) {
            const record = recordCache.get(key);
            if (record !== undefined) {
                return record;
            }
        } else {
            recordCache = new Map();
            resourceCache.set(resourceType, recordCache);
        }

        const record = {
            status: Empty,
            suspender: null,
            value: null,
            error: null,
        };
        recordCache.set(key, record);
        return record;
    }

    function load(emptyRecord, suspender) {
        const pendingRecord = emptyRecord;
        pendingRecord.status = Pending;
        pendingRecord.suspender = suspender;
        suspender.then(
            value => {
                // Resource loaded successfully.
                const resolvedRecord = pendingRecord;
                resolvedRecord.status = Resolved;
                resolvedRecord.suspender = null;
                resolvedRecord.value = value;
            },
            error => {
                // Resource failed to load. Stash the error for later so we can throw it
                // the next time it's requested.
                const rejectedRecord = pendingRecord;
                rejectedRecord.status = Rejected;
                rejectedRecord.suspender = null;
                rejectedRecord.error = error;
            }
        );
    }

    const cache = {
        invalidate() {
            invalidator();
        },
        preload(resourceType, key, miss, missArg) {
            const record = getRecord(resourceType, key);
            switch (record.status) {
            case Empty:
                // Warm the cache.
                var suspender = miss(missArg);
                load(record, suspender);
                return;
            case Pending:
                // There's already a pending request.
                return;
            case Resolved:
                // The resource is already in the cache.
                return;
            case Rejected:
                // The request failed.
                return;
            }
        },
        read(resourceType, key, miss, missArg) {
            const record = getRecord(resourceType, key);
            switch (record.status) {
            case Empty:
                // Load the requested resource.
                var suspender = miss(missArg);
                load(record, suspender);
                throw suspender;
            case Pending:
                // There's already a pending request.
                throw record.suspender;
            case Resolved:
                return record.value;
            case Rejected:
            default:
                // The requested resource previously failed loading.
                var error = record.error;
                throw error;
            }
        },
    };

    cache.$$typeof = CACHE_TYPE;

    return cache;
}
const globalCache = createCache(noop);
export const SimpleCache = createContext(globalCache);

// https://dev.to/swyx/a-walkthrough-of-that-react-suspense-demo--4j6ahttps://dev.to/swyx/a-walkthrough-of-that-react-suspense-demo--4j6a