{"id":20818489,"url":"https://github.com/yusangeng/polygala","last_synced_at":"2026-01-23T07:05:13.759Z","repository":{"id":57327042,"uuid":"116284805","full_name":"yusangeng/polygala","owner":"yusangeng","description":" Toolset about time \u0026 timing.","archived":false,"fork":false,"pushed_at":"2020-11-11T11:24:53.000Z","size":52,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-25T10:29:13.642Z","etag":null,"topics":["asynchronous","macrotask","microtask","polling","timing"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yusangeng.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-01-04T16:52:25.000Z","updated_at":"2020-11-11T11:24:55.000Z","dependencies_parsed_at":"2022-09-21T02:01:26.701Z","dependency_job_id":null,"html_url":"https://github.com/yusangeng/polygala","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/yusangeng/polygala","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yusangeng%2Fpolygala","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yusangeng%2Fpolygala/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yusangeng%2Fpolygala/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yusangeng%2Fpolygala/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yusangeng","download_url":"https://codeload.github.com/yusangeng/polygala/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yusangeng%2Fpolygala/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28682282,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T05:48:07.525Z","status":"ssl_error","status_checked_at":"2026-01-23T05:48:07.129Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["asynchronous","macrotask","microtask","polling","timing"],"created_at":"2024-11-17T21:47:04.132Z","updated_at":"2026-01-23T07:05:13.744Z","avatar_url":"https://github.com/yusangeng.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# polygala\n\n[![TypeScript](https://img.shields.io/badge/lang-typescript-blue.svg)](https://www.tslang.cn/) [![Build Status](https://travis-ci.org/yusangeng/polygala.svg?branch=master)](https://travis-ci.org/yusangeng/polygala) [![Coverage Status](https://coveralls.io/repos/github/yusangeng/polygala/badge.svg?branch=master)](https://coveralls.io/github/yusangeng/polygala?branch=master) [![Npm Package Info](https://badge.fury.io/js/polygala.svg)](https://www.npmjs.com/package/polygala) [![Downloads](https://img.shields.io/npm/dw/polygala.svg?style=flat)](https://www.npmjs.com/package/polygala)\n\n## Abstract\n\nTS library about timing.\n\n## Install\n\n```bash\nnpm install polygala --save\n```\n\n## Usage\n\n### sleep\n\nAsynchronous sleep.\n\n```ts\nimport { sleep } from 'polygala';\n\nasync function main(): Promise\u003cvoid\u003e {\n  await sleep(1000);\n}\n```\n\n### task\n\nSimulative micro/macro task in browser.\n\n```ts\nimport { micro, macro } from 'polygala';\n\nconst task1 = macro(() =\u003e console.log('task1'));\nconst task2 = micro(() =\u003e console.log('task2'));\n\ntask1();\ntask2();\n\n//=\u003e Prints 'task2', 'task1'\n```\n\n### fifo\n\nFIFO promise queue.\n\n```ts\nimport { fifo, sleep } from 'polygala';\n\nasync function fa(): Promise\u003cvoid\u003e {\n  // 2s delay\n  await sleep(2000);\n}\n\nasync function fb(): Promise\u003cvoid\u003e {\n  // 1s delay\n  await sleep(1000);\n}\n\nconst globalFIFOName = Symbol('foobar');\n\nconst a = fifo(fa, globalFIFOName);\nconst b = fifo(fb, globalFIFOName);\n\nlet str = '';\n\na().then(() =\u003e {\n  str += 'Hello';\n});\nb().then(() =\u003e {\n  str += 'World';\n});\n\n//=\u003e str === 'Hello World'\n```\n\n### poll\n\nAn easy-to-use polling implemention.\n\n```ts\nimport { poll } from 'polygala';\n\nconst stop = poll(\n  async (polling) =\u003e {\n    const { url } = polling.context;\n    await fetch(url);\n  },\n  {\n    delay: 3000,\n    limit: 1000, // Repeats at most 1000 times, 0 means NO limit.\n    context: {\n      url: '//foobar.com/heartbeat',\n    },\n    onError: (err) =\u003e {\n      console.error(err);\n      return false; // False means \"Don't stop polling\", if you want to stop, return true.\n    },\n  }\n);\n\n// ...\n\nstop(); // stop polling.\n```\n\n### poll/until\n\nPoll until compare function returns true.\n\n```ts\nimport { poll } from 'polygala';\n\nlet i = 0;\n\ntry {\n  const data = await poll(async () =\u003e i++).until((curr: any) =\u003e curr \u003e 100, 1000);\n} catch (err) {\n  console.log(err.message);\n}\n```\n\n### quittable\n\nQuittable asynchronous task.\n\n```ts\nimport { quittable, sleep } from 'polygala';\nimport ajax from './ajax';\nimport store from './store';\n\nconst task = quittable(\n  async (task) =\u003e {\n    await sleep(1000);\n\n    if (task.quitted) {\n      // Task has been quitted.\n      return;\n    }\n\n    const { url } = task.context;\n    const data = await ajax.get(url);\n\n    if (task.quitted) {\n      return;\n    }\n\n    store.data = data;\n  },\n  // Name of quittable task, null means on name.\n  // A named task would be quitted if a new task with the same name was run.\n  'foobar',\n  // context\n  {\n    url: '//foobar.com/heartbeat',\n  }\n);\n\ntask.run();\n\nsetTimeout((_) =\u003e {\n  task.quit();\n}, 1050);\n```\n\n## API\n\n### sleep\n\nSleep Asynchronously.\n\n```ts\nfunction sleep(milliseconds: number): Promise\u003cvoid\u003e;\n```\n\n### micro \u0026 macro\n\nInvoke simulative micro/macro tasks in browser.\n\n```ts\ntype FProcedure = (...args: any[]) =\u003e void;\n\nfunction micro\u003cFn extends FProcedure\u003e(fn: Fn): Fn;\nfunction macro\u003cFn extends FProcedure\u003e(fn: Fn): Fn;\n```\n\n### fifo\n\nPush an async function and its return value into a FIFO promise queue.\n\n```ts\ntype AsyncFunc\u003cRetType\u003e = (...args: any[]) =\u003e Promise\u003cRetType\u003e;\n\nexport function fifo\u003cFn extends AsyncFunc\u003cvoid\u003e\u003e(fn: Fn, queueName?: symbol): Fn;\nexport function fifo\u003cRetType, Fn extends AsyncFunc\u003cRetType\u003e\u003e(fn: Fn, queueName?: symbol): Fn;\n```\n\n### poll\n\nStart polling.\n\n```ts\n// Polling function type.\ntype PollingFunc\u003cContextType\u003e = (p: Polling\u003cContextType\u003e) =\u003e void;\n\n// Error callbacl type.\ntype ErrorCallback = (error: Error) =\u003e boolean;\n\n// Options type.\ntype PollingOptions\u003cContextType\u003e = {\n  context?: ContextType;\n  delay?: number;\n  limit?: number;\n  onError?: ErrorCallback;\n};\n\n// Function to stop polling.\ntype StopFunc = () =\u003e void;\n\nfunction poll\u003cContextType\u003e(fn: PollingFunc\u003cContextType\u003e, options?: PollingOptions\u003cContextType\u003e): StopFunc;\n```\n\n### quittable\n\nCreate a quittable task.\n\n```ts\ninterface IQuittable\u003cContextType\u003e {\n  quitted: boolean;\n  readonly context: ContextType;\n  quit(): void;\n}\n\ntype FQUITTED = () =\u003e void;\n\nclass Quittable\u003cContextType, RetType\u003e implements IQuittable\u003cContextType\u003e {\n  // ...\n\n  run(): Promise\u003cFQUITTED | RetType\u003e;\n  quit(): void;\n}\n\ntype QuittableCallable\u003cContextType, RetType\u003e = (q: IQuittable\u003cContextType\u003e) =\u003e RetType;\n\nfunction quittable\u003cContextType, RetType = void\u003e(\n  context: ContextType,\n  fn: QuittableCallable\u003cContextType, RetType\u003e\n): Quittable\u003cContextType, RetType\u003e;\n```\n\n### namedQuittable\n\nCreate a named quittable task.\n\nIf you've created a named quittable task, the last task with the same name was quitted automatically.\n\n```ts\nfunction namedQuittable\u003cContextType, RetType = void\u003e(\n  name: symbol,\n  context: ContextType,\n  fn: QuittableCallable\u003cContextType, RetType\u003e\n): Quittable\u003cContextType, RetType\u003e;\n```\n\n### getRunningNamedQuittable\n\nFind the running named quittable task.\n\n```typescript\nfunction getRunningNamedQuittable(name: symbol);\n```\n\n### countdown\n\n```ts\nexport type CountDownOptions = {\n  // Countdown interval, the default value is 1000ms.\n  interval?: number;\n  total: number;\n  onTimeout?: (total: number, countdown: CountDown) =\u003e void;\n  onTick?: (residue: number, total: number, countdown: CountDown) =\u003e void;\n};\n\nexport function countdown(options: CountDownOptions);\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyusangeng%2Fpolygala","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyusangeng%2Fpolygala","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyusangeng%2Fpolygala/lists"}