Skip to content

Commit

Permalink
feat: add fetch support
Browse files Browse the repository at this point in the history
  • Loading branch information
dmnsgn committed May 11, 2022
1 parent deaf152 commit d1d47cb
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 5 deletions.
114 changes: 114 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,24 @@ console.log(text);
## Functions

<dl>
<dt><a href="#fetchText">fetchText(url, options)</a> ⇒ <code>Promise.&lt;string&gt;</code></dt>
<dd><p>Load an item and parse the Response as text</p>
</dd>
<dt><a href="#fetchJson">fetchJson(url, options)</a> ⇒ <code>Promise.&lt;JSON&gt;</code></dt>
<dd><p>Load an item and parse the Response as json</p>
</dd>
<dt><a href="#fetchArrayBuffer">fetchArrayBuffer(url, options)</a> ⇒ <code>Promise.&lt;ArrayBuffer&gt;</code></dt>
<dd><p>Load an item and parse the Response as arrayBuffer</p>
</dd>
<dt><a href="#fetchBlob">fetchBlob(url, options)</a> ⇒ <code>Promise.&lt;Blob&gt;</code></dt>
<dd><p>Load an item and parse the Response as blob</p>
</dd>
<dt><a href="#fetchImage">fetchImage(urlOrOpts, options)</a> ⇒ <code>Promise.&lt;HTMLImageElement&gt;</code></dt>
<dd><p>Load an item, parse the Response as blob and create a HTML Image</p>
</dd>
<dt><a href="#fetchAll">fetchAll(resources)</a> ⇒ <code>Promise.&lt;Object.&lt;string, LoadedResource&gt;&gt;</code></dt>
<dd><p>Loads resources from a named map</p>
</dd>
<dt><a href="#load">load(resources, callback)</a> ⇒ <code>Promise.&lt;Object.&lt;string, LoadedResource&gt;&gt;</code> | <code>undefined</code></dt>
<dd><p>Loads resources from a named map</p>
</dd>
Expand Down Expand Up @@ -93,6 +111,102 @@ console.log(text);
<dd></dd>
</dl>

<a name="fetchText"></a>

## fetchText(url, options) ⇒ <code>Promise.&lt;string&gt;</code>

Load an item and parse the Response as text

**Kind**: global function

| Param | Type |
| ------- | ------------------------ |
| url | <code>RequestInfo</code> |
| options | <code>RequestInit</code> |

<a name="fetchJson"></a>

## fetchJson(url, options) ⇒ <code>Promise.&lt;JSON&gt;</code>

Load an item and parse the Response as json

**Kind**: global function

| Param | Type |
| ------- | ------------------------ |
| url | <code>RequestInfo</code> |
| options | <code>RequestInit</code> |

<a name="fetchArrayBuffer"></a>

## fetchArrayBuffer(url, options) ⇒ <code>Promise.&lt;ArrayBuffer&gt;</code>

Load an item and parse the Response as arrayBuffer

**Kind**: global function

| Param | Type |
| ------- | ------------------------ |
| url | <code>RequestInfo</code> |
| options | <code>RequestInit</code> |

<a name="fetchBlob"></a>

## fetchBlob(url, options) ⇒ <code>Promise.&lt;Blob&gt;</code>

Load an item and parse the Response as blob

**Kind**: global function

| Param | Type |
| ------- | ------------------------ |
| url | <code>RequestInfo</code> |
| options | <code>RequestInit</code> |

<a name="fetchImage"></a>

## fetchImage(urlOrOpts, options) ⇒ <code>Promise.&lt;HTMLImageElement&gt;</code>

Load an item, parse the Response as blob and create a HTML Image

**Kind**: global function

| Param | Type |
| --------- | ----------------------------------------------------------------- |
| urlOrOpts | <code>string</code> \| [<code>ImageOptions</code>](#ImageOptions) |
| options | <code>RequestInit</code> |

<a name="fetchAll"></a>

## fetchAll(resources) ⇒ <code>Promise.&lt;Object.&lt;string, LoadedResource&gt;&gt;</code>

Loads resources from a named map

**Kind**: global function

| Param | Type |
| --------- | -------------------------------------------- |
| resources | <code>Object.&lt;string, Resource&gt;</code> |

**Example**

```js
const resources = {
hello: { text: "assets/hello.txt" },
data: { json: "assets/data.json" },
img: { image: "assets/tex.jpg" },
hdrImg: { binary: "assets/tex.hdr" },
blob: { binary: "assets/blob" },
};

const res = await io.fetchAll(resources);
res.hello; // => DOMString
res.data; // => Object
res.img; // => HTMLImageElement
res.hdrImg; // => ArrayBuffer
res.blob; // => Blob
```

<a name="load"></a>

## load(resources, callback) ⇒ <code>Promise.&lt;Object.&lt;string, LoadedResource&gt;&gt;</code> \| <code>undefined</code>
Expand Down
130 changes: 130 additions & 0 deletions fetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/**
* Load an item and parse the Response as text
* @function
* @param {RequestInfo} url
* @param {RequestInit} options
* @returns {Promise<string>}
*/
export const fetchText = async (url, options = {}) =>
await (await fetch(url, options)).text();

/**
* Load an item and parse the Response as json
* @function
* @param {RequestInfo} url
* @param {RequestInit} options
* @returns {Promise<JSON>}
*/
export const fetchJson = async (url, options = {}) =>
await (await fetch(url, options)).json();

/**
* Load an item and parse the Response as arrayBuffer
* @function
* @param {RequestInfo} url
* @param {RequestInit} options
* @returns {Promise<ArrayBuffer>}
*/
export const fetchArrayBuffer = async (url, options = {}) =>
await (await fetch(url, options)).arrayBuffer();

/**
* Load an item and parse the Response as blob
* @function
* @param {RequestInfo} url
* @param {RequestInit} options
* @returns {Promise<Blob>}
*/
export const fetchBlob = async (url, options = {}) =>
await (await fetch(url, options)).blob();

/**
* Load an item, parse the Response as blob and create a HTML Image
* @function
* @param {string | ImageOptions} urlOrOpts
* @param {RequestInit} options
* @returns {Promise<HTMLImageElement>}
*/
export const fetchImage = async (urlOrOpts, options = {}) => {
const img = new Image();

let src = urlOrOpts;
if (urlOrOpts.url) {
const { url, ...rest } = urlOrOpts;
src = url;
try {
Object.assign(img, rest);
} catch (error) {
return Promise.reject(new Error(error));
}
}

const data = await fetchBlob(src, options);

return await new Promise((resolve, reject) => {
img.addEventListener("load", function load() {
img.removeEventListener("load", load);
resolve(img);
});
img.addEventListener("error", function error() {
img.removeEventListener("error", error);
reject(img);
});

img.src = URL.createObjectURL(data);
});
};

const LOADERS_MAP = {
text: fetchText,
json: fetchJson,
image: fetchImage,
blob: fetchBlob,
binary: fetchArrayBuffer,
};
const LOADERS_MAP_KEYS = Object.keys(LOADERS_MAP);

/**
* Loads resources from a named map
* @function
* @param {Object.<string, Resource>} resources
* @returns {Promise<Object.<string, LoadedResource>>}
*
* @example
* const resources = {
* hello: { text: "assets/hello.txt" },
* data: { json: "assets/data.json" },
* img: { image: "assets/tex.jpg" },
* hdrImg: { binary: "assets/tex.hdr" },
* blob: { binary: "assets/blob" },
* };
*
* const res = await io.fetchAll(resources);
* res.hello; // => DOMString
* res.data; // => Object
* res.img; // => HTMLImageElement
* res.hdrImg; // => ArrayBuffer
* res.blob; // => Blob
*/
export const fetchAll = (resources) => {
const names = Object.keys(resources);

return Promise.allSettled(
names.map(async (name) => {
const res = resources[name];
const loader = LOADERS_MAP_KEYS.find((loader) => res[loader]);
if (loader) return await LOADERS_MAP[loader](res[loader]);
return Promise.reject(
new Error(`io.load: unknown resource type "${Object.keys(res)}".
Resource needs one of ${LOADERS_MAP_KEYS.join("|")} set to an url.`)
);
})
).then((values) =>
Object.fromEntries(
Array.from(
values.map((v) => v.value || v.reason),
(v, i) => [names[i], v]
)
)
);
};
61 changes: 61 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ <h1>pex-io</h1>
json: "assets/color.json",
image: "assets/pex.png",
binary: "assets/data.bin",
blob: "assets/hello.txt",
errorNotFound: "assets/not-found.ext",
};

Expand All @@ -58,9 +59,12 @@ <h1>pex-io</h1>
"callback-batch": { ...assetState },
async: { ...assetState },
"async-batch": { ...assetState },
fetch: { ...assetState, blob: null },
"fetch-batch": { ...assetState, blob: null },
error: { ...assetState, error: null },
"image-options": { all: null, readOnly: null, urlOnly: null },
};
window.state = state;

const app = () => () => {
return [
Expand Down Expand Up @@ -176,6 +180,63 @@ <h1>pex-io</h1>
state["async-batch"].binary = res.data;
})();

// fetch
(async () => {
try {
state.fetch.text = await io.fetchText(ASSETS.text);
} catch (error) {
state.fetch.text = error;
console.log("fetch", error);
}
try {
state.fetch.json = await io.fetchJson(ASSETS.json);
} catch (error) {
state.fetch.json = error;
console.log("fetch", error);
}
try {
state.fetch.image = await io.fetchImage(ASSETS.image);
} catch (error) {
state.fetch.image = error;
console.log("fetch", error);
}
try {
state.fetch.binary = await io.fetchArrayBuffer(ASSETS.binary);
} catch (error) {
state.fetch.binary = error;
console.log("fetch", error);
}
try {
state.fetch.blob = await io.fetchBlob(ASSETS.blob);
state.fetch.blob = await state.fetch.blob.text();
} catch (error) {
state.fetch.blob = error;
console.log("fetch", error);
}
})();

// fetch-batch
(async () => {
let res;
try {
res = await io.fetchAll({
hello: { text: ASSETS.text },
color: { json: ASSETS.json },
pex: { image: ASSETS.image },
data: { binary: ASSETS.binary },
blob: { blob: ASSETS.blob },
});
} catch (err) {
res = err;
console.log("fetch batch", filterResultsErrors(err));
}
state["fetch-batch"].text = res.hello;
state["fetch-batch"].json = res.color;
state["fetch-batch"].image = res.pex;
state["fetch-batch"].binary = res.data;
state["fetch-batch"].blob = await res.blob.text();
})();

// Error
(() => {
io.loadText(ASSETS.errorNotFound, (err, text) => {
Expand Down
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export { default as loadText } from "./loadText.js";
export { default as loadJSON } from "./loadJSON.js";
export { default as loadImage } from "./loadImage.js";
export { default as loadBinary } from "./loadBinary.js";
export * from "./fetch.js";
7 changes: 2 additions & 5 deletions load.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,11 @@ function load(resources, callback) {
Promise.allSettled(
names.map(async (name) => {
const res = resources[name];

const loader = LOADERS_MAP_KEYS.find((loader) => res[loader]);
if (loader) return await LOADERS_MAP[loader](res[loader]);
return Promise.reject(
new Error(
`io.load: unknown resource type "${Object.keys(res)}".
Resource needs one of ${LOADERS_MAP_KEYS.join("|")} set to an url.`
)
new Error(`io.load: unknown resource type "${Object.keys(res)}".
Resource needs one of ${LOADERS_MAP_KEYS.join("|")} set to an url.`)
);
})
).then((values) => {
Expand Down

0 comments on commit d1d47cb

Please sign in to comment.