{"id":15050470,"url":"https://github.com/mozilla/jsthreads","last_synced_at":"2025-10-04T13:31:22.647Z","repository":{"id":8843888,"uuid":"10549728","full_name":"mozilla/jsThreads","owner":"mozilla","description":"INACTIVE - http://mzl.la/ghe-archive - Cooperative multithreading in Javascript using generators","archived":true,"fork":false,"pushed_at":"2019-03-28T04:16:00.000Z","size":92,"stargazers_count":18,"open_issues_count":0,"forks_count":9,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-05-22T20:00:33.535Z","etag":null,"topics":["inactive","unmaintained"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mozilla.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-06-07T12:50:10.000Z","updated_at":"2024-01-07T11:06:08.000Z","dependencies_parsed_at":"2022-08-30T05:52:38.106Z","dependency_job_id":null,"html_url":"https://github.com/mozilla/jsThreads","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla%2FjsThreads","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla%2FjsThreads/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla%2FjsThreads/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mozilla%2FjsThreads/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mozilla","download_url":"https://codeload.github.com/mozilla/jsThreads/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219876611,"owners_count":16554771,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["inactive","unmaintained"],"created_at":"2024-09-24T21:26:46.379Z","updated_at":"2025-10-04T13:31:17.359Z","avatar_url":"https://github.com/mozilla.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"jsThreads\n=========\n\nCooperative \"multithreading\" in Javascript using generators.\n\n\nMotivation\n----------\n\nI want to avoid callback hell.  Promises do a good job, but force you to manage\nnamespace by including parameters to your then() functions.  Threads have the\nbenefit of (local) namespace pollution.\n\nBenefits\n--------\n\n* **Multiple threads of control** - All the thrill of multi-threaded programming, with none of the race conditions, deadlocking, or corrupted state you have from real threading.\n* **Procedural style** - Functions can be written in familiar procedural style, instead of callback style.\n* **try/catch blocks work** - Because of he procedural style, throwing and catching exceptions continue to work as expected \n* **Threads are objects** - Thread objects allow you to monitor peer thread state and interrupt peer threads.\n\n\nFeatures\n--------\n\n**Create a New Thread**\n\nCreate a new thread of control, which is left to its own devices, and the caller can continue with its own work. \n\n    Thread.run(function*(){\n        //DO WORK\n\t});\n\n\n\n**Synchronous Calling Style**\n\n\tThread.run(function*(){\n\t\tvar a = yield (requestDataFromServer());\n\t\t//DO WORK\n\t\tvar b = yield (anotherRequestToServer(a));\n\t\t//MORE WORK\n\t\tvar c = yield (yetAnotherRequest(b));\n\t});\n\nAll function* calls are in order, as if written synchronously.  The jsThread library will weave this function with others to achieve parallelism.\n\n\n**Wait for Thread to Complete**\n\n\tvar t=Thread.run(function*(){...});\t//MAKE THREAD\n\tyield (Thread.join(t));\t\t\t\t//WAIT TO FINISH\n\nThe ```join()``` function will return a structure (```{\"threadResponse\":value}```)\nwith the last value handled by the joinee thread (`t`).  This value is either the last\nyielded value or a thrown exception.\n\nJoining a thread will demand all child threads are joined too.\n\n**Sleep**\n\n\tyield (Thread.sleep(1000));  //JUST ONE SECOND\n\n```sleep()``` can be interrupted with the ```kill()``` from another thread.\n\n**Cooperate**\n\nWhen performing long running operations on the main thread, it is a good idea to\noccasionally yield control to the other tasks and threads waiting to run.\n\n\tyield (Thread.yield());            //LET OTHER THREADS RUN\n\nA call to ```yield()``` may, or may not suspend, depending on the amount of time\nthat has passed since the last ```suspend()```\n\nThe ```Thread.yield()``` call is a little slow:  The call defers to the\ntrampoline, which calls Thread.yield(), which returns a generator, which is then\ncalled by the trampoline, which returns the Thread.YIELD constant, which reminds\nthe trampoline to check if it's time to yield to another task.  It is more\ndirect to simply provide the constant:\n\n    yield (Thread.YIELD);              //LET OTHER THREADS RUN (alternate)\n\nAdmittedly, this breaks the standard ```yield (functionCall())``` form.\n\n**Stop Thread Early**\n\n\tvar t=Thread.run(function*(){...}); //MAKE THREAD\n\tt.kill();                           //KILL IT (Interrupt)\n\nUse this to ```abort()``` server requests or stop sleeping prematurely.  The\nkilled thread will then receive a ``Thread.Interrupt``` exception.\nThis exception can be caught just like any other.  It is important your code\nproperly recognizes and handles this exception to shutdown cleanly.\n\nKilling a thread will also kill all children, which can include ajax requests\nand other scheduled processing.\n\n**Adding Children**\n\n    myThread.addChild({\"kill\":function(){...}})\n\nChild threads are added automatically to the ```Thread.currentThread``` when\na thread is made.  You are not limited to Threads: Any object that\nhas  a ```kill``` or ```abort``` function can be added.\n\n\n\n**Suspend/Resume Threads**\n\nYou will inevitably require your threads interact with other callback-style\nJavascript libraries.  To do this without busy waiting you need to *suspend*\nand *resume* your threads. [JSONP.js](./examples/JSONP.js) is an example of\nhow to achieve this:\n\n    var getJSON = function*(url) {\n        //ASK FOR A CALLBACK THAT CAN RESUME THE CURRENT THREAD\n        var callback = yield (Thread.Resume);\n\n        //THIS CURRENT THREAD WILL RESUME WHEN callback IS CALLED\n        var req = $.getJSON(url, callback);\n\n        //SUSPEND UNTIL RESUME CALLBACK IS EXECUTED\n        var json = yield (Thread.suspend(req));\n\n        //RETURN\n        yield (json);\n    };//function\n\nThe idea is to ask the jsThreads system for a resume function:  When called,\nthis function will resume the current thread.  In this case, the resume function\nis used as a callback and fed into a familiar JQuery call.  Your final step is\nto suspend the thread and trust the resume function is eventually called.  When\nthe thread does resume, the first argument of the resume function (the callback)\nwill be accessible as a yielded value.\n\n**AJAX**\n\nThe AJAX callback style (with its success() and error() callbacks) is pervasive.\nUse the ```Thread.call()``` function to specifically provide these callbacks,\nyield the success() argument, and throw an exception if error() is called.\n[Ajax.js](.examples/Ajax.js) is a example of how to use it:\n\n    var ajax = function*(param) {\n        yield Thread.call($.ajax, param);\n    };//function\n\n\nDrawbacks\n---------\n\nHere are some of complications to look out for\n\n####Only Works in Firefox (and Chrome with experimental javascript on)####\n\nGenerators have been around for a while, but other browsers (and js engines) have only\nstarted to implement them.  To use generators in Chrome enable\n[experimental javascript](chrome://flags/#enable-javascript-harmony).\n\n####Must be a Generator####\n\nA common mistake is to forget the star (*) in the function definition.  This will make\nit appear as if nothing happens\n\n  - **BAD:**\n\n        Thread.run(function(){\n            $(\"#message\").html(\"Hi there\");\n        });\n\n\n  - **GOOD:**\n\n        Thread.run(function*(){\n            $(\"#message\").html(\"Hi there\");\n        });\n\n####Accidentally Calling Generators Directly####\n\nWith so many generators in your code, you may find yourself calling them like\nnormal functions.  This is bad.  These 'normal' functions return generator objects,\nand do not fully execute on first call.   If you find your function is not\nexecuting, this is probably the cause.\n\n - **BAD:**\n\n        doSomeSetup();          //YOU CAN'T TELL, BUT THIS IS A\n                                //GENERATOR.  IT WILL SEEM TO DO NOTHING\n\n - **GOOD:**\n\n        yield (doSomeSetup());  //NOW IT WILL WORK\n        \nThis happens often to me when I am joining threads:\n\n - **BAD:**\n\n        Thread.join(A);     /HEY! Where are A's artifacts!?\n\n - **GOOD:**\n\n        yield Thread.join(A);   //Oh! I forgot to wait for A to finish.\n        \n\n####Hard to Debug####\n\nBecause ```Thread``` calls all generators directly, it can be impossible to see the\nstack trace you expect.\n\nAvoid this problem by keeping your threaded code from making deep threaded calls.\nIf you need deep logic, it is better implemented with regular functions, called by\nthe threaded code.\n\n####Impossible States with Debugger####\n\nWhen your debugger is on, AND you have your code paused, AND there are pending\nresponses, all bets are off.  The pending response will trigger the javascript\nengine to run despite the debugger, and mess with your program state.\n\nThis is not a problem with jsThreads, it is a problem with debugging any\njavascript program; I just want you to be aware your program can be\nachieve *impossible* states when you are debugging.\n\n####Can not us JS Functors####\n\nYou must pass a generator to ```Thread.run()```.  Javascript's functor style can prevent\nelegant threaded code:\n\n  - **BAD:**\n\n        Thread.run(function*(){\n            $.each(array, function(item){\n                yield (callBackToServer())  //YIELD IS IN NESTED ANONYMOUS FUNCTION\n            });\n        });\n\n  - **GOOD:**\n\n        Thread.run(function*(){\n            for(var i=0;i\u003carray.length;i++){\n                yield (callBackToServer())\t//YIELD IS PART OF PASSED FUNCTION\n            };\n        });\n\n  - **BETTER?** (it depends)\n\n        $.each(array, function(item){\n            Thread.run(function*(){\n                yield (callBackToServer()) //YIELD IS PART OF PASSED FUNCTION\n            });\n        });\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmozilla%2Fjsthreads","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmozilla%2Fjsthreads","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmozilla%2Fjsthreads/lists"}