3. k6 脚本基础:JavaScript 语法速览、模块导入、VU 与迭代、options 配置与 export default 函数

在编写 k6 压测脚本之前,必须掌握其核心的脚本模型。k6 脚本本质上是 JavaScript(ES6+),但运行在 Go 语言编写的 goja 引擎中,因此不支持浏览器 DOM API。本章将拆解 k6 脚本的五大基础构件,为后续编写多阶段压测场景打下坚实根基。

3.1 JavaScript 语法速览(k6 环境限定)

k6 支持 ES6 模块语法、箭头函数、模板字符串、解构赋值等现代特性,但存在以下关键限制:

特性 支持情况 说明
let / const ✅ 完全支持 推荐使用 const 声明不可变引用
箭头函数 ✅ 完全支持 () => {} 常用于回调与默认函数
模板字符串 ✅ 完全支持 `${var}` 拼接 URL 或日志
解构赋值 ✅ 完全支持 const { key } = obj
Promise / async/await ⚠️ 有限支持 仅用于 http.asyncRequest 等少数 API
DOM / window / document ❌ 不支持 k6 不是浏览器,无渲染引擎
CommonJS (require) ❌ 不支持 必须使用 ES6 import
💡 实战建议: 在 k6 脚本中始终使用 const 和 let,避免 var。所有 HTTP 调用必须通过 k6 内置模块,不能使用 fetch 或 axios。

3.2 k6 模块导入机制

k6 使用 ES6 import 语法加载模块。模块分为三类:

  • 内置模块:k6/http、k6/check、k6/metrics、k6/encoding 等,直接通过路径导入。
  • 本地模块:将公共函数或配置抽取为 .js 文件,使用相对路径导入。
  • npm 模块:k6 不支持直接 npm install,但可通过 k6 扩展(xk6)或 jslib.k6.io 加载部分社区库。
// 导入内置模块
import http from 'k6/http';
import { check, sleep } from 'k6';
import { Rate, Trend } from 'k6/metrics';

// 导入本地模块(假设文件位于同一目录)
import { generatePayload } from './helpers.js';
import { BASE_URL, HEADERS } from './config.js';

// 导入远程模块(k6 官方 CDN)
import { uuidv4 } from 'https://jslib.k6.io/k6-utils/1.4.0/index.js';
⚠️ 常见错误: 不要使用 require(),k6 引擎会直接报错 require is not defined。所有导入必须写在文件顶部,不支持动态 import()。

3.3 VU 与迭代:k6 的执行模型

理解 VU(Virtual User) 和 迭代(Iteration) 是编写正确脚本的前提。k6 的执行模型可以用下图概括:

k6 执行模型:VU 与迭代 初始化阶段 import / 全局变量 VU 池 N 个独立 VU 实例 迭代循环 export default 函数 单个 VU 的生命周期(每个 VU 独立重复) setup() (可选) default() 迭代主体 teardown() (可选) sleep() 思考时间 重复执行直到达到迭代次数或时长
🔑 核心概念:
  • VU:一个独立的虚拟用户,拥有自己的 JS 运行时和全局变量副本。VU 之间不共享内存。
  • 迭代:每个 VU 重复执行 export default 函数一次,称为一次迭代。
  • 初始化:每个 VU 在首次运行时执行一次脚本顶部的代码(import、全局变量声明),之后只重复执行 default 函数。

3.4 options 配置:定义压测行为

export const options 是 k6 脚本的配置中心,用于定义 VU 数量、持续时间、阈值、阶段等。以下是一个包含多阶段场景的 options 示例:

export const options = {
  // 基础配置
  vus: 10,                    // 初始 VU 数
  duration: '30s',            // 测试持续时间

  // 阶段配置(覆盖 vus 和 duration)
  stages: [
    { duration: '30s', target: 20 },   // 阶段1:30秒内从 10 升至 20 VU
    { duration: '1m', target: 20 },    // 阶段2:保持 20 VU 运行 1 分钟
    { duration: '30s', target: 0 },    // 阶段3:30秒内降至 0 VU
  ],

  // 阈值(SLO 门禁)
  thresholds: {
    http_req_duration: ['p(95)<500'],  // 95% 请求响应时间 < 500ms
    http_req_failed: ['rate<0.01'],     // 失败率 < 1%
  },

  // 其他常用配置
  iterations: 1000,           // 总迭代次数(与 duration 互斥)
  maxRedirects: 10,           // 最大重定向次数
  insecureSkipTLSVerify: true,// 跳过 TLS 证书验证
};
配置项 类型 说明
vus number 并发虚拟用户数
duration string 测试运行时长(如 '30s'、'5m')
stages array 多阶段压测配置,每个阶段包含 duration 和 target
thresholds object 性能门禁,定义通过/失败条件
iterations number 总迭代次数(与 duration 二选一)
scenarios object 高级场景配置(可混合多种执行器)
📌 阶段配置优先级: 当同时设置 vus/duration 和 stages 时,stages 会覆盖前两者。建议在复杂场景中只使用 stages 或 scenarios,避免混淆。

3.5 export default 函数:迭代的执行体

export default function() 是每个 VU 每次迭代都会执行的入口函数。它必须是一个函数,不能是箭头函数(因为需要绑定 this 上下文)。

import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  vus: 5,
  duration: '10s',
  thresholds: {
    http_req_duration: ['p(95)<200'],
  },
};

export default function () {
  // 1. 发送 HTTP 请求
  const res = http.get('https://test.k6.io');

  // 2. 执行检查(断言)
  check(res, {
    'status is 200': (r) => r.status === 200,
    'response time < 300ms': (r) => r.timings.duration < 300,
  });

  // 3. 模拟思考时间
  sleep(1);
}
⚙️ 执行流程:
  1. k6 启动后,先执行脚本顶部的 import 和全局变量声明(初始化阶段)。
  2. 根据 options 创建指定数量的 VU。
  3. 每个 VU 独立、并发地重复调用 export default function(),直到达到 duration 或 iterations 限制。
  4. 每次调用之间,sleep() 控制迭代间隔,模拟真实用户行为。

3.6 完整脚本结构示例

将以上知识点整合为一个可运行的 k6 脚本模板:

// 1. 模块导入
import http from 'k6/http';
import { check, sleep, group } from 'k6';
import { Rate, Trend } from 'k6/metrics';

// 2. 自定义指标
const myFailRate = new Rate('my_failed_requests');
const myTrend = new Trend('my_response_time');

// 3. 配置
export const options = {
  stages: [
    { duration: '10s', target: 10 },
    { duration: '20s', target: 10 },
    { duration: '10s', target: 0 },
  ],
  thresholds: {
    my_failed_requests: ['rate<0.05'],
    http_req_duration: ['p(95)<1000'],
  },
};

// 4. 默认函数(迭代主体)
export default function () {
  group('用户登录流程', function () {
    const payload = JSON.stringify({ username: 'test', password: '123' });
    const params = { headers: { 'Content-Type': 'application/json' } };

    const res = http.post('https://api.example.com/login', payload, params);

    const passed = check(res, {
      '登录成功': (r) => r.status === 200,
      '返回 ': (r) => r.json('') !== undefined,
    });

    myFailRate.add(!passed);
    myTrend.add(res.timings.duration);
  });

  sleep(1);
}
⚠️ 避坑指南:
  • 不要在 export default 外部编写需要重复执行的逻辑——它只会在初始化时运行一次。
  • 不要在脚本中使用 console.log 打印大量数据,会严重影响性能。使用 k6 的 metrics 或 check 记录结果。
  • 每个 VU 的全局变量是隔离的,不要依赖 VU 间共享状态。如需共享,使用 k6/execution 模块的 vu.idInTest 或外部数据源。