@browserless/function

中文文档
14.1.0发布于 2026/10/28MITCommonJS近 30 天下载 4246

在安全浏览器沙盒中执行任意的JavaScript代码,可访问页面 DOM和网络.

中文使用文档
文档目录15 节
  1. 安装
  2. 关于
  3. 这个软件包做什么
  4. 使用量
  5. 访问页面
  6. 可用上下文
  7. 结果对象
  8. 减员
  9. 扩展页
  10. 主机页面
  11. 选项
  12. 实例
  13. 如何适合在单体
  14. 依赖关系
  15. 许可证
browserless browserless

Powered by microlink.io Last version Coverage Status NPM Status

@ 浏览器无/ 功能: 在浏览器沙盒内任意运行 JavaScript .

见 函数节 我们的网站有更多信息.

安装

使用 npm :

npm install @browserless/function --save

关于

此软件包提供了 安全沙盒 用于运行任意 JavaScript 代码,可访问浏览器页面。 它在一个孤立的VM环境中执行用户提供的功能,可选择访问Puppeteer的页面API.

这个软件包做什么

这个 @browserless/function 软件包允许您 :

  • 执行任意 JavaScript 在安全、孤立的VM沙盒里
  • 访问浏览器页面 从沙盒内取出 用于 DOM 操作
  • 抓取控制台输出 和执行概况数据
  • 通过自定义数据 到运行时的沙盒函数
  • 处理错误优雅 有结构化结果对象

使用量

首先,通过给工厂打电话来创建函数实例:

const createFunction = require('@browserless/function')()

你可以选择通过一个 tmpdir 用于沙盒工作目录 :

const createFunction = require('@browserless/function')({ tmpdir: '/tmp/functions' })

然后使用它来运行任意 JavaScript :

// Simple function without page access
const code = ({ query }) => query.value * 2

const myFn = createFunction(code)
const result = await myFn('https://example.com', { query: { value: 21 } })

console.log(result)
// => { isFulfilled: true, value: 42, profiling: {...}, logging: {...} }

访问页面

当您引用代码时 page,无浏览器自动提供访问 Puppeteer 页面:

const createFunction = require('@browserless/function')()

// Function with page access
const code = async ({ page }) => {
  const title = await page.title()
  const content = await page.evaluate(() => document.body.innerText)
  return { title, content }
}

const scraper = createFunction(code)
const result = await scraper('https://example.com')

console.log(result)
// => { isFulfilled: true, value: { title: 'Example', content: '...' }, ... }

可用上下文

沙盒函数接收这些属性 :

财产说明
url目标 URL 传递到函数( 不需要浏览器)
page傀儡 页次 对象(如果在代码中引用)
device设备描述符 userAgent 财务报告和审定财务报表 viewport
...opts运行时通过的任何自定义选项

用于您函数的传递值 args。它们被保存在运行时间选项之外,所以一个名为 code, (中文(简体) ), source 或者说 vmOpts 到达您的函数而不是更改其运行方式 :

const myFn = createFunction(({ code }) => code, { args: { code: 'abc' } })
await myFn('https://example.com') // => { isFulfilled: true, value: 'abc', ... }

// per-call args merge over the ones given at creation
await myFn('https://example.com', { args: { code: 'xyz' } }) // value: 'xyz'

args 以相同名称赢得其他自定义选项. response 财务报告和审定财务报表 url 从运行时间来取胜 args也一样 page,当函数运行时;不使用的函数 page 还收到 args.page。 。 。 . device 从运行时间,和 args 不能设置它.

结果对象

该函数返回结构化结果 :

财产说明
isFulfilledtrue 如果执行成功, false 如果出错
value返回值(成功)或出错对象(失败)
profiling执行时间和资源使用情况(见下文)
logging抓取控制台输出( E)log, (中文(简体) ), warn, (中文(简体) ), error页:1

剖析

这个 profiling 对象包含相位时间和资源数据:

财产说明
phases.compile编译沙盒脚本的时间( ms)
phases.spawn产卵时间(毫秒)
phases.run执行用户功能的时间( ms)
phases.total壁点时间共计
cpuCPU 消耗时间(毫秒)
memory峰值内存使用量 (字节)

减员

打电话 .teardown() 在工厂实例中清理沙盒资源:

const createFunction = require('@browserless/function')({ tmpdir: '/tmp/functions' })

// ... use createFunction ...

await createFunction.teardown()

扩展页

附加额外方法于 page. JSON 值成为了同步获取器. 函数作为协同方法内含( )this 是页面; 需要时使用函数而不是箭头 this) (中文(简体) ). 如果用户功能只使用这些方法,则 Chromium 不启动 :

const myFn = createFunction(({ page }) => page.html(), {
  extendPage: { url, html }
})

const result = await myFn('https://example.com')
// => { isFulfilled: true, value: html, ... }

主机页面

附加方法于 page 表示主机在用户函数调用它们时决定,而不是在运行前决定的值. 工作功能从未达到任何成本 :

const myFn = createFunction(({ page }) => page.content(), {
  hostPage: { content: () => fetchThePage(url) }
})

const result = await myFn('https://example.com')
// => { isFulfilled: true, value: html, ... }, and fetchThePage ran once

fetchThePage 运行, 因为函数等待 content返回函数 420 没有触摸 page 从来没有触发它, 也没有树枝它不采取:

const myFn = createFunction('async ({ page }) => (false ? await page.content() : "skipped")', {
  hostPage: { content: () => fetchThePage(url) }
})

const result = await myFn('https://example.com')
// => { isFulfilled: true, value: 'skipped', ... }, and fetchThePage never ran

与 extendPage,方法本身停留在主机上,而不是被序列化入隔离;调用在制作时会穿过频道. 它的论点和结果仍然跨越该频道,所以两者都必须是该频道能够携带的价值:a BigInt例如,拒绝而不是解决这一呼吁.

这两种类型都可以坐在同一页上,或者算作满足了这个方法,所以只使用这些功能的函数不会启动Chromium. 两个名字上的一个是 extendPage 值,而且该主机方法无法达到.

同样的方法和论据每跑一次就能解决. 允许每跑32个不同的电话; vmOpts.maxHostCalls 更改盖子。 隔离会运行不可信代码并可以直接到达通道,因此将每个参数视为不可信输入. 每个 hostPage 值必须是函数.

选项

const myFn = createFunction(code, {
  // Browserless instance factory
  getBrowserless: () => require('browserless')(),
  
  // Attempts on the `getPage` path, where there is no context to replace and
  // this is the only retry. The default path takes its retry count from the
  // browserless context instead.
  retry: 2,
  
  // Execution timeout in milliseconds
  timeout: 30000,
  
  // Extra methods on `page`. JSON values become async getters; functions
  // are inlined as async methods. If the function only uses these methods,
  // Chromium is not started.
  extendPage: {
    url,
    html
  },

  // Methods on `page` the host resolves when the function calls them. The
  // method stays on the host and one the function never reaches is never
  // resolved, though arguments and results still cross the channel and must
  // be values it can carry. Counts as satisfying that method, like extendPage.
  hostPage: {
    content: () => fetchThePage(url)
  },

  // Options passed to browserless.goto()
  gotoOpts: {
    scripts: ['https://cdn.example.com/library.js'],
    waitUntil: 'networkidle0'
  },
  
  // VM sandbox options (passed to isolated-function)
  vmOpts: { /* ... */ },

  // Values for your function, spread into its argument. Never read as a
  // runtime option. Must be a plain object.
  args: { code: 'abc' },

  // Run against a page that is already navigated, instead of creating a
  // context and navigating. It replaces that path, so `getBrowserless` is not
  // consulted when it is set. No `goto` happens and the page is never closed:
  // whoever supplied it owns its lifetime. Pass `response` when you have it,
  // so the function still sees `_response`. `timeout` bounds how long the
  // caller waits. It leaves the page open, and the snippet plus its isolate
  // subprocess keep running until the snippet returns or the page is closed.
  // `device` and `response` are optional. Without a device, the `{ userAgent,
  // viewport }` a snippet sees is read off the page, so it matches what the
  // default path reports; pass your own to override it.
  getPage: async () => ({ page, device, response })
})

重用已装入的呼叫器的一页, 因此目标被获取一次 . getPage 替换上下文和辅助路径,所以 getBrowserless 没有 咨询了这一呼吁:

const { page, response } = await somethingThatAlreadyNavigated(url)

const result = await createFunction(code, {
  getPage: async () => ({ page, response })
})(url)

await page.close()

片段在连接到的隔离中运行 browserWSEndpoint这样 page.browser() 访问浏览器上的每一个页面, 不只是它是一个 掌声. strictTarget 决定哪一页,不是它所能达到的。 这个 在导航路径上,它已经是真实的了, 在一个上下文中,它更为重要 跨任务共享: 将共享视为信任边界 此套件无法 强制你.

timeout 拒绝调用,并打开页面。 片断及其 隔离子进程持续运行, 所以将页面视为繁忙 : 别管它 直到工作结束,或关闭它。 关闭页面结束片断 .

从 browserless 需求 keepPage,从 evaluate 解决后立即关闭页面 :

let page
await context.evaluate(
  currentPage => {
    page = currentPage
    return currentPage.content()
  },
  { keepPage: true }
)(url)

保留一个页面会重新启动它的密切监视器 。 新窗口是 evaluate 编号 : withPage 超时,从移交中计量。 完成或关闭 在窗口结束前页。 一会儿 getPage 呼叫有自己的超时 当评价窗口结束时, 包括当 这一呼吁正在执行中。 设定评估超时时间以覆盖 后续行动.

实例

与页面元素的互动

const createFunction = require('@browserless/function')()

const code = async ({ page }) => {
  await page.waitForSelector('button.submit')
  await page.type('input', '[email protected]', { delay: 200 })
  await page.click('button.submit')
  await page.waitForNavigation()
  return page.title()
}

const clickAndGetTitle = createFunction(code)
const result = await clickAndGetTitle('https://example.com')

输入外部脚本

const createFunction = require('@browserless/function')()

const code = ({ page }) => page.evaluate('jQuery.fn.jquery')

const getjQueryVersion = createFunction(code, {
  gotoOpts: {
    scripts: ['https://code.jquery.com/jquery-3.6.0.min.js']
  }
})

const result = await getjQueryVersion('https://example.com')
// => { isFulfilled: true, value: '3.6.0', ... }

在沙盒中使用 npm 模块

const createFunction = require('@browserless/function')()

const code = async ({ page }) => {
  const _ = require('lodash')
  const text = await page.evaluate(() => document.body.innerText)
  return _.words(text).length
}

const countWords = createFunction(code)
const result = await countWords('https://example.com')

处理错误

const createFunction = require('@browserless/function')()

const code = () => {
  throw new Error('Something went wrong')
}

const myFn = createFunction(code)
const result = await myFn('https://example.com')

console.log(result.isFulfilled) // => false
console.log(result.value.message) // => 'Something went wrong'

如何适合在单体

这个 扩展功能包它没有被接入 browserless 核心 – 需要可以触摸一页的沙盒时安装.

依赖关系

软件包目的
@browserless/errors错误正常化和打出错误
isolated-function通过儿童程序确保被沙箱处决
require-one-of自动检测无浏览器安装
acorn 编号 : acorn-walkAST 解析以检测代码中的页面使用

许可证

无法浏览/ 函数 © 微链接,在 麻省理工学院 执照.
作者和维护者 微链接 由来自 捐助者。 。 。 .

这个 标志 设计由 辛赫工作室。 。 。 .

微链接.io • GitHub 软件 微链克 • X @microlinkhq (英语)

版本与发布记录

@browserless/function 共发布 235 个版本,首次发布于 2021/03/18;过去 12 个月发布了 74 个版本。

版本发布日期距今
14.1.0latest2026/10/2811 天前
14.0.302026/10/2316 天前
14.0.292026/10/2316 天前
14.0.252026/10/1425 天前
14.0.242026/10/1425 天前
14.0.222026/10/1326 天前

关于 @browserless/function 的常见问题

@browserless/function 是什么?

在安全浏览器沙盒中执行任意的JavaScript代码,可访问页面 DOM和网络.

如何安装 @browserless/function?

在项目目录运行 npm install @browserless/function,或使用 pnpm add / yarn add / bun add。

@browserless/function 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/browserless__function 是否存在。

@browserless/function 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@browserless/function 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >= 20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@browserless/function 可以商用吗?

@browserless/function 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@browserless/function 的下载量有多少?

根据 npm 官方下载统计,@browserless/function 在 2026/10/09 – 2026/11/07 这 30 天内被下载 4,246 次,日均约 142 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@browserless/function 还在维护吗?

最新版本 14.1.0 发布于 2026/10/28(11 天前);至今共发布 235 个版本,其中过去 12 个月发布了 74 个;首次发布于 2021/03/18。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。