diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8e206f5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/dist +/node_modules +/package-lock.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..ebacb85 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# Greenlet + +> Move an async function into its own thread. +> +> A simplified single-function version of [workerize](https://github.com/developit/workerize). + +The name is somewhat of a poor choice, but it was [available on npm](https://npm.im/greenlet). + +## Installation & Usage + +```sh +npm i -S greenlet +``` + +Accepts an async function with, produces a copy of it that runs within a Web Worker. + +``` +greenlet(Function) -> Function +``` + + +## Example + +```js +import greenlet from 'greenlet' + +let get = greenlet(async url => { + let res = await fetch(url) + return await res.json() +}) + +console.log(await get('/foo')) +``` + + +## License + +[MIT](https://oss.ninja/mit/developit) diff --git a/greenlet.js b/greenlet.js new file mode 100644 index 0000000..b7987a2 --- /dev/null +++ b/greenlet.js @@ -0,0 +1,25 @@ +/** Move an async function into its own thread. + * @param {Function} fn The (async) function to run in a Worker. + */ +export default function greenlet(fn) { + let w = new Worker(URL.createObjectURL(new Blob([ + 'onmessage='+( + f => ({ data }) => Promise.resolve().then( + () => f.apply(f, data[1]) + ).then( + d => { postMessage([data[0], null, d]); }, + e => { postMessage([data[0], ''+e]); } + ) + )+'('+fn+')' + ]))), + c = 0, + p = {}; + w.onmessage = ({ data: [c,e,d] }) => { + p[c][e?1:0](e||d); + delete p[c]; + }; + return (...a) => new Promise( (y, n) => { + p[++c] = [y, n]; + w.postMessage([c, a]); + }); +} \ No newline at end of file diff --git a/greenlet.test.js b/greenlet.test.js new file mode 100644 index 0000000..77e73f3 --- /dev/null +++ b/greenlet.test.js @@ -0,0 +1,25 @@ +import greenlet from 'greenlet'; + +describe('greenlet', () => { + it('should return an async function', () => { + let g = greenlet( () => 'one' ); + expect(g).toEqual(jasmine.any(Function)); + expect(g()).toEqual(jasmine.any(Promise)); + }); + + it('should invoke sync funtions', async () => { + let foo = greenlet( a => 'foo: '+a ); + + let ret = await foo('test'); + expect(ret).toEqual('foo: test'); + }); + + it('should invoke async funtions', async () => { + let bar = greenlet( a => new Promise( resolve => { + resolve('bar: '+a); + })); + + let ret = await bar('test'); + expect(ret).toEqual('bar: test'); + }); +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..274ba83 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "greenlet", + "version": "0.1.0", + "description": "Move an async function into its own thread.", + "source": "greenlet.js", + "main": "dist/greenlet.js", + "module": "dist/greenlet.m.js", + "scripts": { + "build": "microbundle", + "test": "eslint *.js && karmatic" + }, + "eslintConfig": { + "extends": "eslint-config-developit" + }, + "files": [ + "greenlet.js" + ], + "repository": "developit/greenlet", + "keywords": [ + "greenlet", + "thread", + "async", + "worker", + "web worker" + ], + "author": "Jason Miller (http://jasonformat.com)", + "license": "MIT", + "homepage": "https://github.com/developit/greenlet", + "devDependencies": { + "eslint": "^4.16.0", + "eslint-config-developit": "^1.1.1", + "karmatic": "^1.0.6", + "microbundle": "^0.4.2" + } +}