{"id":22283794,"url":"https://github.com/veaba/done","last_synced_at":"2025-07-23T15:32:44.327Z","repository":{"id":104582137,"uuid":"264893101","full_name":"veaba/done","owner":"veaba","description":"A web framework for deno. (a noob demo).","archived":false,"fork":false,"pushed_at":"2020-06-12T05:40:27.000Z","size":98,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-01-30T17:39:45.346Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/veaba.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-05-18T09:35:39.000Z","updated_at":"2020-06-12T05:40:30.000Z","dependencies_parsed_at":null,"dependency_job_id":"10615b88-d83d-4ed0-bad6-2ec9d5c1ec00","html_url":"https://github.com/veaba/done","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/veaba%2Fdone","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/veaba%2Fdone/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/veaba%2Fdone/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/veaba%2Fdone/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/veaba","download_url":"https://codeload.github.com/veaba/done/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245535444,"owners_count":20631294,"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":[],"created_at":"2024-12-03T16:42:18.859Z","updated_at":"2025-03-25T19:51:47.374Z","avatar_url":"https://github.com/veaba.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Done\n\n\u003e https://github.com/veaba/done\n\n前期为了方便开发，嵌入到 https://github.com/veaba/blog 里面的 `src/done`\n\n现在只是非常的基础，在原标准库 `http/server.ts` 里面再做一次封装\n\n预期\n  - 使用最底层的库，从新封装一层才好(现在使用标准库)\n  - 吸收了`oak`、 `koa`的特性  \n  - 参考:\n    - [oak](https://github.com/oakserver/oak)\n    - [koa](https://github.com/koajs/koa)\n    - [fastity](https://github.com/fastify/fastify)\n\n  \n## TODO LIST、feature\n\n|feat | 描述 |\n|-----|------|\n|Router||\n|get||\n|post||\n|put||\n|res:image||\n|res:audio||\n|res:video||\n|res:js||\n|res:css||\n|res:file||\n|res:download file||\n|https||\n|http2||\n|res:json|√|\n|res:string|√|\n|res:array|√|\n|res:object||\n|res:jsonp||\n|res:blob||\n|res:binay||\n|res:stream||\n|res:websocket||\n|set headers||\n|redirect||\n|throw http code||\n  \n      \n## 优化指标\n- TODO 使用`fast-json-stringify` 替换原生的`JSON.stringify()`\n- TODO radix-tree 来处理router，见 https://github.com/delvedor/find-my-way\n- TODO [使用样式重用对象和函数](https://github.com/mcollina/reusify)\n- TODO 闭包问题，避免嵌套闭包\n  - [see](https://mcollina.github.io/take-your-http-server-to-ludicrous-speed/#34)\n\nbad\n```js\nfunction process (bigdata, cb) {\n  remoteCall(bigdata, function (err, something) {\n    storeSomething(something, function (err, res) {\n      // this function is short-lived and hard to optimize\n      // bigdata is still in scope!\n      cb(null, res * 2)\n    })\n  })\n}\n```\n\ngood\n```js\nfunction process (bigdata, cb) {\n  remoteCall(bigdata, function (err, something) {\n    // bigdata exits scope here\n    callStoreSomething(something, cb)\n  })\n}\nfunction callStoreSomething(something, cb) {\n  /* this function can be optimized! */\n  storeSomething(something, function (err, res) {\n    cb(null, res * 2)\n  })\n}\n```\n## 警告！这是一个练手的demo\n\n\u003e deno run --allow-net app.ts\n\n```typescript \n\n// app.ts\n\nimport { Done } from 'https://raw.githubusercontent.com/veaba/done/master/mod.ts'\nconst done = new Done() // maybe need some options ...\nconsole.log('done 实例==\u003e', done)\n// TODO 不要回调了，使用async的方法 \ndone.get('/',(ctx:any)=\u003e{\n  ctx.response.body=\"Hello world!\"          // 支持string\n  // ctx.body = {hello:\"world\"}             // 支持 json\n  // ctx.body = 2020                        // 支持 number\n})\n\ndone.listen(9999)\n    .then(() =\u003e {\n        console.log(`Start Done server on port ${port}`)\n    })\n\n```\n\n## 疑问\n\n- 需要理解use 的中间期间设计理念\n- 使用一个中间期间数组去遍历执行完回调函数\n- declare 用法是什么\n```typescript\n// declare 用法是什么\ndeclare module xx{\n\n}\n\n```\n\n- xx.d.ts 怎么用\n- /// 三斜线的用法\n\n- 每次更新后，更新一下实例的get\n解决办法：回调\n\n- TODO 应该如何更好的定义一个class 的形状\n  - interface\n  - type\n  - namespace\n  - module\n  - declare\n\n- `\u003cT\u003e` \n- extends   用法\n- super     用法\n\n- [学习-声明文件](https://ts.xcatliu.com/basics/declaration-files)\n\n\n- declare var 声明全局变量\n  - 全局修改模式,let、const（常用）\n  - 仅用于声明，勿具体实现代码逻辑\n- declare function 声明全局方法\n```ts\ndeclare function jQuery(domReadyCallback: () =\u003e any): any;\n```\n- declare class 声明全局类\n\n\n- ts 如何在class内部个定时器，然后执行实例的函数，给实例返回参数\n```ts\n// src/Animal.d.ts\n\ndeclare class Animal {\n    name: string;\n    constructor(name: string);\n    sayHi(): string;\n}\n\n// 具体实现将报错：// ERROR: An implementation cannot be declared in ambient contexts.\n```\n- declare enum 声明全局枚举类型\n- declare namespace 声明（含有子属性的）全局对象\n- interface 和 type 声明全局类型\n- export 导出变量\n- export namespace 导出（含有子属性的）对象\n- export default ES6 默认导出\n- export = commonjs 导出模块\n- export as namespace UMD 库声明全局变量\n- declare global 扩展全局变量\n- declare module 扩展模块\n- /// \u003creference /\u003e 三斜线指令\n\n- 如何调用Deno内置方法\n``` ts\nconst listen = Deno.listen\n```\n\n## class 声明\n\n\n### 关键字\n- public    默认\n- private   可以被继承，无法在实例中访问\n- protected 类似private 构造函数是protected，无法实例化，只能被继承\n- readonly  只读属性，无法被修改clone\n- static    静态属性，在类内部使用时需加类名，无法被实例访问，\n\n\n## ts 与es 的箭头函数\n\n注意不要混淆了 TypeScript 中的 =\u003e 和 ES6 中的 =\u003e。\n在 TypeScript 的类型定义中，=\u003e 用来表示函数的定义，左边是输入类型，需要用括号括起来，右边是输出类型。\n在 ES6 中，=\u003e 叫做箭头函数，应用十分广泛，可以参考 ES6 中的箭头函数。\n\n## 异步回调\n\n```js\n//express 的回调方法\nfunction cool(a, fn) {\n    console.log('a==\u003e', a)\n    console.log('fn==\u003e', fn('xx', 'hah'))\n}\n\nconst he = cool('/abs', (z, x) =\u003e {\n    console.log('he=\u003e', arguments)\n    console.log('回调的结果==\u003e', z, x)\n})\n\n// TODO 使用promise async/await\n\n```\n\n## TODO: 如何测试框架性能？\n\n- string 和 其他类型的处理速度\n- 不使用函数作为回调，而使用proxy。经过测试，循环100、1000次对比，均三倍运行速度优于函数回调\n\n## TODO: koa 路由输入 （洋葱模型）\n\n实在太简单了，还是得要内置一波常用的东西，先实现功能，等待后续稳定再剥离，总结完善框架\n\n```js\nif (ctx.request.path == '/about') {\n    ctx.response.type = 'html'; // 指定返回类型为 html 类型\n    ctx.response.body = 'this is about page \u003ca href=\"/\"\u003eGo Index Page\u003c/a\u003e';\n  } else {\n    ctx.response.body = 'this is index page';\n}\n```\n\n## TODO: 知识盲区\n\n- Unit8Array\n- buf\n\n## TODO: deno 返回的req\n\n```text\n\nServerRequest {\n done: Promise { \u003cpending\u003e },\n _contentLength: undefined,\n _body: null,\n finalized: false,\n conn: ConnImpl {\n  rid: 4,\n  remoteAddr: { hostname: \"127.0.0.1\", port: 15442, transport: \"tcp\" },\n  localAddr: { hostname: \"127.0.0.1\", port: 9999, transport: \"tcp\" }\n },\n r: BufReader {\n  r: 565,\n  w: 565,\n  eof: false,\n  buf: Uint8Array(4096) [\n       71,  69,  84,  32,  47, 102,  97, 118, 105,  99, 111, 110,  46, 105,  99,\n      111,  32,  72,  84,  84,  80,  47,  49,  46,  49,  13,  10,  72, 111, 115,\n      116,  58,  32,  49,  50,  55,  46,  48,  46,  48,  46,  49,  58,  57,  57,\n       57,  57,  13,  10,  67, 111, 110, 110, 101,  99, 116, 105, 111, 110,  58,\n       32, 107, 101, 101, 112,  45,  97, 108, 105, 118, 101,  13,  10,  80, 114,\n       97, 103, 109,  97,  58,  32, 110, 111,  45,  99,  97,  99, 104, 101,  13,\n       10,  67,  97,  99, 104, 101,  45,  67, 111, 110,\n      ... 3996 more items\n    ],\n  rd: ConnImpl {\n   rid: 4,\n   remoteAddr: { hostname: \"127.0.0.1\", port: 15442, transport: \"tcp\" },\n   localAddr: { hostname: \"127.0.0.1\", port: 9999, transport: \"tcp\" }\n  }\n },\n method: \"GET\",\n url: \"/favicon.ico\",\n proto: \"HTTP/1.1\",\n protoMinor: 1,\n protoMajor: 1,\n headers: Headers { host: 127.0.0.1:9999, connection: keep-alive, pragma: no-cache, cache-control: no-cache, user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36, sec-fetch-dest: image, accept: image/webp,image/apng,image/*,*/*;q=0.8, sec-fetch-site: same-origin, sec-fetch-mode: no-cors, referer: http://127.0.0.1:9999/, accept-encoding: gzip, deflate, br, accept-language: zh-CN,zh;q=0.9,en;q=0.8, cookie: Hm_lvt_e8002ef3d9e0d8274b5b74cc4a027d08=1579594807,1579660868,1579742421 },\n w: BufWriter {\n  usedBufferBytes: 39,\n  err: null,\n  writer: ConnImpl {\n   rid: 4,\n   remoteAddr: { hostname: \"127.0.0.1\", port: 15442, transport: \"tcp\" },\n   localAddr: { hostname: \"127.0.0.1\", port: 9999, transport: \"tcp\" }\n  },\n  buf: Uint8Array(4096) [\n       72,  84,  84,  80,  47,  49,  46,  49,  32,  50,  48,  48,  32,  79,  75,\n       13,  10,  99, 111, 110, 116, 101, 110, 116,  45, 108, 101, 110, 103, 116,\n      104,  58,  32,  49,  56,  13,  10,  13,  10,  72, 101, 108, 108, 111,  32,\n      119, 111, 114, 108, 100,  32, 104, 116, 109, 108,  32,  10,   0,   0,   0,\n        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,\n      ... 3996 more items\n    ]\n }\n}\n\n```\n\n## 设置headers\n\n```ts\n// haha,要new 实例\nconst headers=new Headers({\"Content-Type\":\"text/html;charset=utf-8\"})\nconst req={respond:(x)=\u003ex}\nreq.respond({\n  body: this.body || \"没有任何内容！\",\n  headers\n});\n```\n\n## Deno 编码解码\n\n```ts\nconst str = \"Hello world 世界\"\nconst encoder = new TextEncoder()\nconst decoder = new TextDecoder()\n\nconst x = encoder.encode(str)\n\nconsole.log('encode==\u003exxx==\u003e', x)\nconst y = decoder.decode(x)\nconsole.log('decode==\u003eyyy==\u003e', y)\n```\n\n## Header Content-Type\n\n- text: `text/plain`\n- multipart: `multipart/mixed`\n- application: `application/octet-stream`、`application/json`\n- message: E-mail \n- image: 静态图片\n- audio: 音频数据\n- video: 视频\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fveaba%2Fdone","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fveaba%2Fdone","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fveaba%2Fdone/lists"}