Last active
April 4, 2023 16:54
-
-
Save monochromer/7cbfc253152805f9d6572d4c9649f617 to your computer and use it in GitHub Desktop.
WIP. Потоковая выдача html через генераторы
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function isGenerator(target) { | |
| return target[Symbol.toStringTag] === 'GeneratorFunction'; | |
| } | |
| function isIterable(obj) { | |
| if (obj === null || obj === void 0) { | |
| return false; | |
| } | |
| if (typeof obj === 'string') { | |
| return false; | |
| } | |
| return typeof obj[Symbol.iterator] === 'function'; | |
| } | |
| function html(strings, ...values) { | |
| const items = strings.reduce((acc, item, index) => { | |
| acc.push(item); | |
| if (index < values.length) { | |
| acc.push(values[index]); | |
| } | |
| return acc; | |
| }, []).filter(Boolean); | |
| return function* (context) { | |
| for (const item of items) { | |
| switch (true) { | |
| case (isIterable(item)): { | |
| yield* item; | |
| break; | |
| } | |
| case (item instanceof Function): { | |
| const res = item(context); | |
| if (isIterable(res)) { | |
| yield* res; | |
| } else { | |
| yield res; | |
| } | |
| break; | |
| } | |
| /* TODO: async yield | |
| case (item instanceof Promise): { | |
| yield await item | |
| } | |
| */ | |
| default: { | |
| yield item; | |
| } | |
| } | |
| } | |
| } | |
| } | |
| const headerTemplate = html` | |
| <header> | |
| <h1>Header Title</h1> | |
| </header> | |
| `; | |
| const footerTemplate = html` | |
| <footer> | |
| footer | |
| </footer> | |
| `; | |
| const mainTemplate = html` | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>${ctx => ctx.title}</title> | |
| </head> | |
| <body> | |
| ${headerTemplate()} | |
| <nav> | |
| <ul>${[ | |
| `<li><a href="#">Home</a></li>`, | |
| `<li><a href="#">Solutions</a></li>`, | |
| `<li><a href="#">Blog</a></li>`, | |
| `<li><a href="#">Career</a></li>`, | |
| `<li><a href="#">Contacts</a></li>`, | |
| ]}</ul> | |
| </nav> | |
| <main>${ctx => ctx.main}</main> | |
| ${footerTemplate()} | |
| </body> | |
| </html> | |
| `; | |
| function delay(time) { | |
| return new Promise(resolve => setTimeout(resolve, time)); | |
| } | |
| require('http') | |
| .createServer(async (req, res) => { | |
| const ctx = { | |
| title: 'some top title', | |
| main: 'body' | |
| } | |
| res.writeHead(200, { | |
| 'Content-Type': 'text/html' | |
| }); | |
| for (let chunk of mainTemplate(ctx)) { | |
| res.write(chunk); | |
| await delay(1000); | |
| } | |
| res.end(); | |
| }).listen(3000, () => { | |
| console.log('http://localhost:3000') | |
| }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment