拓冰建站拓冰建站
首页 / 资讯中心 / 正文

ES6 Generator异步随机数生成:蓝桥杯Web模拟题解析

这次我们来看一道蓝桥杯 Web 应用开发方向的模拟题解析用 ES6 生成器异步产生随机数。题目只有十几个字但实际覆盖的知识点并不少包括 Generator 状态机、Promise 异步流程控制、随机数 API 选型以及一个简单的 Web 接口封装。把这条链路完整跑通之后你既能在裁判系统里写出符合要求的答案也可以顺手做一个带 HTTP 接口的随机数批量生成服务。先给结论整篇文章不需要引入任何第三方框架原生 JavaScript 就能完成浏览器控制台和 Node.js 环境都可以直接验证。如果你正在备赛蓝桥杯或者想搞懂 ES6 Generator 到底怎么配合异步流程这篇文章可以收藏备用。下面会按照“题目设计 → 前置知识 → 环境准备 → 基础实现 → 异步实现 → 接口与批量任务 → 测试验证 → 排错 → 最佳实践”的顺序展开所有代码都可以单独复制运行。1. 核心能力速览在开始写代码之前先用一张表把这道模拟题的能力边界说清楚。这样你判断“这个技术点是否适合我现在用”会更直接。能力项说明题目类型蓝桥杯 Web 应用开发方向模拟题解析ES6 异步编程与随机数应用核心知识点ES6 Generator、Promise、异步流程控制、随机数生成、HTTP 接口封装运行环境现代浏览器控制台或 Node.js 16无需第三方依赖启动方式浏览器打开 HTML文件 /node 文件名.js/node server.js主要功能生成指定范围随机数、模拟异步生成延迟、批量生成、HTTP 接口返回是否支持 API支持提供 Node.js 原生http模块接口示例是否支持批量任务支持通过循环迭代生成器获取多个随机数随机数方案Math.random()入门演示加密安全场景建议使用 Web Crypto API 或 Node.jscrypto.randomInt适合场景蓝桥杯备赛、ES6 异步学习、随机数工具接口原型需要特别说明的是这道题本质是“用 Generator 管理异步流程”而不是“随机数本身只能异步生成”。真实开发中Math.random()是同步的真正有意义的是后面这套“Promise Generator 手动迭代”的流程控制方式。把这一点理解清楚题目才算真正吃透。2. 题目设计与考察点分析这一类蓝桥杯模拟题通常不会只考一个语法点而是会把多个基础能力串起来。参考实际备赛时的常见考法可以设计出如下题目描述设计一个 Web 应用要求使用 ES6 Generator 函数封装随机数生成逻辑每次获取随机数时模拟异步等待等待结束后返回一个[min, max]范围内的整数在浏览器页面点击按钮后能连续获取多个随机数并展示到页面上随机数来源的 API 要可切换至少能区分普通随机数和加密安全随机数如果通过 Node.js 运行需要实现一个 HTTP 接口通过GET /api/random返回单个随机数通过GET /api/random/batch?count5返回批量随机数。输入输出示例输入范围 1-100数量 5 输出[23, 87, 56, 9, 42]表面看输出结果只是几个随机数但评分时可以拆出的考察点非常多Generator 的基本用法是否理解function*、yield、next()的配合方式惰性求值生成器函数体不会在调用时立即执行而是每次next()才推进一次异步流程控制能否把 Generator 产生的 Promise 正确消费掉随机数 API 选择是否知道Math.random()的局限以及加密安全随机数的使用场景接口封装与批量任务能否把底层逻辑封装成可访问的服务并控制批量请求的边界。使用边界上这道题适合以下读者正在备赛蓝桥杯 Web 应用开发方向的学生、想补 ES6 Generator 异步知识的开发者、需要快速搭一个随机数生成接口的前端工程师。不适合完全不熟悉 JavaScript 基础语法的人直接上手建议至少先掌握函数、Promise、数组方法这三个前置能力。3. 前置知识ES6 Generator 与异步流程控制3.1 Generator 是什么Generator 是 ES6 提供的一种可以暂停和恢复执行的函数。定义时在function后面加一个星号function* randomGenerator(min, max) { yield Math.random(); yield Math.random(); } const gen randomGenerator(1, 10); console.log(gen); // 生成器对象函数体还没有执行调用生成器函数时函数体不会立即运行而是返回一个生成器对象。只有调用next()之后代码才会执行到第一个yield然后暂停在那里const result gen.next(); console.log(result); // { value: 随机数, done: false }next()返回值是一个对象包含value和done两个字段。value是yield后面表达式的值done表示生成器是否已经结束。这个“暂停 恢复”能力正是异步流程控制的基础。3.2 为什么 Generator 可以控制异步异步代码的根本问题是“不知道什么时候结束”。Promise 解决了回调地狱但 Promise 链仍然需要手动管理。而 Generator 可以做到把异步任务包装成 Promise再用yield把它抛出外部通过next()拿到这个 Promise等它 resolve 之后再调用一次next(value)把结果传回生成器内部。看起来比较绕但本质就是一个手动版的async/await。实际上async/await就是 Generator 和 Promise 的语法糖。理解这一点你对 async/await 的掌握会更扎实。3.3 随机数 API 怎么选这道题涉及随机数最容易丢分的地方就是 API 选型。简单对比一下方案是否加密安全使用场景注意事项Math.random()否页面展示、洗牌演示、游戏随机实现简单但不能用于密码、令牌、抽奖等需要不可预测性的场景crypto.getRandomValues()是安全令牌、抽奖、密钥相关需要安全上下文file://协议下不一定可用Node.jscrypto.randomInt()是Node.js 服务端随机数使用方便直接返回整数题目要求是模拟练习用Math.random()入门没问题但代码注释里最好写清楚如果需要安全随机数应该换成加密安全 API。这也是竞赛评分中“代码健壮性”和“工程意识”的一部分。4. 环境准备与前置条件这道题虽然简单但环境还是需要简单确认一下。推荐使用 Node.js 环境因为后面要验证 HTTP 接口。如果你电脑上已经有 Node.js直接进入下一步如果没有也可以先用浏览器 F12 控制台跑完同步和异步生成器部分。4.1 检查 Node.js 和 npm打开终端执行node -v npm -v如果输出类似v18.x.x、9.x.x说明环境可用。如果没有输出需要先安装 Node.js LTS 版本。4.2 初始化项目目录建议单独建一个目录避免和已有文件混在一起mkdir es6-random-generator cd es6-random-generator npm init -ynpm init -y会生成一个最简package.json。本示例不依赖第三方模块所以不需要安装任何依赖。如果你不想用 Node.js可以直接在浏览器里新建一个 HTML 文件在script标签中写代码用浏览器打开即可。后面接口部分会用到 Node.js但核心的 Generator 异步逻辑浏览器也能跑。4.3 准备编辑器推荐 VS Code装不装插件都行。只要你写的.js文件和.html文件编码是 UTF-8中文输出就不会乱码。5. 基础实现用同步生成器产生随机数先从最简单的版本开始。创建一个random-sync.js内容如下// random-sync.js function* randomGenerator(min 0, max 100) { while (true) { yield Math.floor(Math.random() * (max - min 1)) min; } } const gen randomGenerator(1, 100); console.log(gen.next().value); console.log(gen.next().value); console.log(gen.next().value);在终端运行node random-sync.js预期输出是三行1到100之间的整数例如42 7 86这里有几个关键点while (true)让生成器进入无限循环每次next()都会停在yield处调用方按需取值Math.floor(Math.random() * (max - min 1)) min是生成区间内整数的标准写法注意max - min 1不能少生成器是惰性的不会一次把所有随机数算出来内存占用很低。如果你把gen.next().value改成gen.next()会发现输出变成了{ value: 42, done: false }这样的对象。这是初学 Generator 最容易搞混的地方next()返回的是对象真正的值在.value上。6. 异步实现用 ES6 生成器异步产生随机数6.1 用 Promise 包装随机数题目要求“异步产生”这里可以用setTimeout模拟一次耗时操作。比如模拟从服务端获取随机数每次生成前等待 100 到 300 毫秒。创建random-async.js// random-async.js function createAsyncRandom(min 0, max 100) { return new Promise((resolve) { const random Math.floor(Math.random() * (max - min 1)) min; const delay Math.floor(Math.random() * 200) 100; setTimeout(() { resolve(random); }, delay); }); } function* asyncRandomGenerator(min 0, max 100) { while (true) { yield createAsyncRandom(min, max); } }注意这里生成器yield出去的不是随机数而是一个 Promise。调用方拿到 Promise 之后需要等它 resolve。6.2 手动迭代生成器最简单的消费方式就是手动调用next()const gen asyncRandomGenerator(1, 100); gen.next().value.then((value) { console.log(第一次异步随机数, value); return gen.next().value; }).then((value) { console.log(第二次异步随机数, value); });每次gen.next()都会产生一个新的 Promise然后用.then()处理结果。这样做的问题是如果次数多了代码会变得很啰嗦和回调地狱没有本质区别。6.3 用递归驱动批量任务更常见的做法是写一个调度函数从生成器里持续取 Promiseresolve 后再继续取下一个。下面的代码会批量生成total个随机数function collectRandom(generator, total) { const result []; function step(index) { if (index total) { return Promise.resolve(result); } const next generator.next(); if (next.done) { return Promise.resolve(result); } return Promise.resolve(next.value).then((value) { result.push(value); return step(index 1); }); } return step(0); } const batchGen asyncRandomGenerator(1, 100); collectRandom(batchGen, 5).then((numbers) { console.log(批量结果, numbers); });运行node random-async.js预期输出类似批量结果 [ 23, 87, 56, 9, 42 ]这段代码的思路是自己实现一个微型调度器把 Generator 产生的 Promise 一个个消费掉。如果你理解了这个流程再去看 async/await就是换了一套更顺手的语法。6.4 async/await 版本对比同样功能用 async/await 写会直观很多async function batchCollect(generator, total) { const result []; for (let i 0; i total; i) { const random await generator.next().value; result.push(random); } return result; } const gen2 asyncRandomGenerator(1, 100); batchCollect(gen2, 5).then((numbers) { console.log(async/await 版本, numbers); });这里要特别强调await generator.next().value是可行的因为generator.next().value返回的是 Promise而await就是在等 Promise resolve。这就是 Generator 和 Promise 天然衔接的证明。7. 封装为 Web 接口与批量任务题目说“Web 应用开发实战”所以只写控制台脚本还远远不够。这里用 Node.js 原生模块写一个随机数接口服务不需要 Express 等框架竞赛环境里更稳。7.1 HTTP 服务代码创建server.js// server.js const http require(http); const { randomInt } require(crypto); const host 127.0.0.1; const port 3000; function* asyncRandomGenerator(min 0, max 100) { while (true) { const random randomInt(min, max 1); yield new Promise((resolve) { setTimeout(() resolve(random), 50); }); } } function sendJSON(res, statusCode, data) { res.writeHead(statusCode, { Content-Type: application/json; charsetutf-8 }); res.end(JSON.stringify(data)); } const server http.createServer((req, res) { const url new URL(req.url, http://${req.headers.host}); if (url.pathname /api/random) { const gen asyncRandomGenerator(1, 100); gen.next().value.then((value) { sendJSON(res, 200, { code: 0, data: value }); }); return; } if (url.pathname /api/random/batch) { const count Number(url.searchParams.get(count) || 5); const safeCount Math.min(Math.max(count, 1), 1000); const gen asyncRandomGenerator(1, 100); const result []; function run(i) { if (i safeCount) { sendJSON(res, 200, { code: 0, data: result, total: result.length }); return; } gen.next().value.then((value) { result.push(value); run(i 1); }); } run(0); return; } sendJSON(res, 404, { code: 404, message: not found }); }); server.listen(port, host, () { console.log(随机数接口已启动http://${host}:${port}); });启动服务node server.js如果终端输出随机数接口已启动http://127.0.0.1:3000说明服务已经跑起来了。这里用crypto.randomInt替代Math.random()是因为接口服务的随机数可能被用于抽奖或令牌场景加密安全的随机数来源更合适。7.2 curl 调用接口新开一个终端直接请求curl http://127.0.0.1:3000/api/random返回示例{code:0,data:73}批量接口curl http://127.0.0.1:3000/api/random/batch?count5返回示例{code:0,data:[23,87,56,9,42],total:5}注意count参数即使传一个很大的数字接口也会限制到 1000这是为了防止批量任务把服务拖垮。7.3 Python 调用接口很多备赛学生会用 Python 写自动化测试这里给一个简单的请求示例import requests url http://127.0.0.1:3000/api/random/batch params {count: 5} response requests.get(url, paramsparams, timeout5) print(response.status_code) print(response.json())如果requests库没有安装先执行pip install requests7.4 批量任务设计建议接口服务暴露出来之后批量任务需要考虑几个点限制数量不要让调用方一次请求 10 万个随机数count要设上限逐步生成生成器一次只产出一个 Promise用递归或循环逐步消费不会把所有任务一次性压进内存失败重试这里模拟的是本地setTimeout不容易失败如果是真实远程接口建议在消费 Promise 时加上重试逻辑日志记录每次批量请求记录时间戳、数量、结果条数方便排查问题。8. 功能测试与效果验证一个功能能不能过评审最终要看测试结果。建议你按下面的表格逐项验证测试项输入预期结果判断标准同步生成器执行random-sync.js输出三行整数数字都在 1 到 100 之间异步生成器执行random-async.js输出数组包含 5 个整数数组长度等于 5元素类型为 number范围边界生成器传min1, max1始终输出 1不会出现其他数字单个接口GET /api/randomJSON 返回code0data是整数批量接口GET /api/random/batch?count5JSON 返回数组数组长度等于 5参数上限GET /api/random/batch?count10000实际生成 1000 个接口不被拖垮404 分支请求不存在的路径JSON 返回code404状态码为 404运行测试时建议开启 Node.js 的进程观察在另一个终端执行node --trace-warnings server.js这样可以更早发现未处理的 Promise 警告。对于大批量生成可以通过任务管理器或系统监视器观察 Node.js 进程的内存占用。由于这套实现是逐个消费 Promise内存增幅通常远低于一次性Array.from({ length: n }, ...)的做法。9. 常见问题与排查方法备赛时最容易踩的坑如下直接对照排查。问题现象可能原因排查方式解决方案调用生成器函数后没有任何输出没有调用next()函数体不会执行检查是否写了gen.next()调用迭代器取.valuenext()返回对象而不是数字直接把next()当成随机数打印返回值看结构使用gen.next().value控制台输出[object Promise]生成器 yield 出去的是 Promise没消费检查是否用了.then或awaitgen.next().value.then(...)浏览器中crypto.getRandomValues报错file://协议下安全 API 不可用换成localhost或 HTTPS 环境用Math.random()演示或启动本地服务器接口 404请求路径或查询参数写错打印url.pathname和searchParams对齐/api/random和/api/random/batch端口被占用3000 端口被其他进程占用终端报EADDRINUSE修改port为 3001 等批量任务结果顺序不对使用了Promise.all并发获取观察生成顺序使用递归或for await逐个消费随机数质量不满足要求安全场景使用Math.random()评估是否需要不可预测性切换 Web Crypto API 或crypto.randomInt其中“生成器不执行”是最多人踩的坑本质原因是 Generator 的惰性求值。记住一句话调用生成器函数只是创建对象next()才是真正的执行动作。10. 高分答案的组织与最佳实践如果你要把这道题的答案写到竞赛系统里建议不要只堆代码而是按模块拆分并加一些关键注释。先写最小可运行示例先跑通同步生成器再改成异步最后加接口。不要一开始就全写在一起。生成器只负责状态流转把“随机数怎么产生”和“是否异步等待”拆开随机数 API 可以通过参数传入方便测试时替换。批量任务要有边界接口参数限制、最大数量、失败重试这些工程细节是加分项。善用 Node.js 内置模块不要为了一个随机数接口硬装 Express原生http模块足够而且裁判环境更可控。注释里写清楚安全边界说明Math.random()不适合密码学场景建议换成加密安全随机数来源。这体现的不只是代码能力更是工程意识。还有一个很重要的合规提醒如果题目后续扩展成真实业务场景涉及抽奖、权限令牌、用户数据必须使用加密安全的随机数来源并且确认你的使用场景符合平台规则和法律法规。本文所有代码仅用于学习和技术验证不要直接用于高风险生产环境而不做安全评估。11. 总结与下一步这道模拟题真正值得掌握的三个点第一Generator 的暂停和恢复机制是异步流程控制的核心第二async/await本质上就是 Generator 加 Promise 的语法糖第三随机数 API 的选型要跟着场景走不是所有随机数都只能用Math.random()。最容易踩的坑是next()返回的是一个对象而不是直接的值。后续如果你想继续扩展可以尝试把上面的生成器换成真实接口请求比如从远程服务获取随机数或者把批量生成改为流式输出每生成一个推给前端一次。这样你对 Generator 的异步控制能力会有更深的理解。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门