GithubHelp home page GithubHelp logo

worker-sandbox's Introduction

worker-sandbox npm GitHub license Build Status Coverage Status

Javascript Web Workers Sandbox.

中文文档

Usage

Installation

npm install --save worker-sandbox

OR

yarn add worker-sandbox

Quickstart

To build a runInContext function as an example:

import Sandbox from 'worker-sandbox' // Import module

async function runInContext(code, context) {
  try {
    let sandbox = new Sandbox() // Create a sandbox instance
    await sandbox.assign(context) // Assign the context of the sandbox
    return await sandbox.eval(code) // Run the code
  } finally {
    sandbox.destroy() // Destroy the Web Worker instance in the sandbox
  }
}

runInContext('sayHelloWorld()', {
  helloWorld: 'hello world'
, sayHelloWorld() {
    return helloWorld
  }
})
.then(console.log) // hello world

API

class Sandbox()

Use the new operator to create a sandbox instance, and the Sandbox class constructor has no arguments.

let sandbox = new Sandbox()
sandbox instanceof Sandbox // true

async Sandbox#eval(code: string | Function[, destroyTimeout: number]) : any

Eval code in the sandbox. If the destroyTimeout parameter (milliseconds) is provided, a TimeoutError exception is returned when the execution code exceeds the specified time.

let sandbox = new Sandbox()
  , result = await sandbox.eval('"hello world"')
result === 'hello world' // true

Use destroyTime

let sandbox = new Sandbox()
try {
  await sandbox.eval('while(true) {}', 1000)
} catch(e) {
  e instanceof TimeoutError // true
}

async Sandbox#execute(code: string | Function[, destroyTimeout: number]) : void

No return value version of Sandbox#eval.

let sandbox = new Sandbox()
  , result = await sandbox.execute('"hello world"')
result === undefined // true

Sandbox#context : { [string]: any }

This is an asynchronous Proxy object that can be used as syntactic sugar for Sandbox#set, Sandbox#get, Sandbox#remove, Sandbox#call.

let sandbox = new Sandbox()

// Get the full context
await sandbox.context // {}

// Set the value of a specific path
sandbox.context.helloWorld = 'hello world'

// Get the value of a specific path
await sandbox.context.helloWorld === 'hello world' // true

// Set a specific path as a function
sandbox.context.sayHelloWorld = function(speaker) {
  return `${ speaker }: ${ helloWorld }`
}

// Call a function of a specific path (the actual function runs in the sandbox)
await sandbox.context.sayHelloWorld('Sandbox') === 'Sandbox: hello world'

// Remove the value of a specific path
delete sandbox.context.helloWorld
delete sandbox.context.sayHelloWorld
await sandbox.context.helloWorld === undefined // true
await sandbox.context.sayHelloWorld === undefined // true

async Sandbox#set(path: Array | string, value: any) : void

Set the value of a specific path in the sandbox context.

let sandbox = new Sandbox()
await sandbox.set('arr', [])
await sandbox.set('arr[0]', 'hello')
await sandbox.set('arr[1]', 'world')
await sandbox.set(['arr[2]'], 'arr[2]')
(await sandbox.context.arr).join(' ') === 'hello world' // true
await sandbox.context['arr[2]'] === 'arr[2]' // true

Equivalent to

let sandbox = new Sandbox()
await sandbox.set('arr', [])
await sandbox.set(['arr', '0'], 'hello')
await sandbox.set(['arr', '1'], 'world')
await sandbox.set(['arr[2]'], 'arr[2]')
(await sandbox.context.arr).join(' ') === 'hello world' // true
await sandbox.context['arr[2]'] === 'arr[2]' // true

Equivalent to

let sandbox = new Sandbox()
sandbox.context.arr = []
sandbox.context.arr[0] = 'hello'
sandbox.context.arr[1] = 'world'
sandbox.context['arr[2]'] = 'arr[2]'
(await sandbox.context.arr).join(' ') === 'hello world' // true
await sandbox.context['arr[2]'] === 'arr[2]' // true

async Sandbox#assign(obj: { [string]: any }) : void

It is the Object.assign() for Sandbox#context.

let sandbox = new Sandbox()
await sandbox.assign({
  hello: 'hello'
, world: 'world'
, sayHelloWorld() {
    return `${ hello } ${ world}`
  }
, 'functions.sayHelloWorld': function() {
    return `${ hello } ${ world}`
  }
})
await sandbox.context.sayHelloWorld() === 'hello world' // true
await sandbox.context['functions.sayHelloWorld']() === 'hello world' // true

Equivalent to

let sandbox = new Sandbox()
Object.assign(sandbox.context, {
  hello: 'hello'
, world: 'world'
, sayHelloWorld() {
    return `${ hello } ${ world}`
  }
, 'functions.sayHelloWorld': function() {
    return `${ hello } ${ world}`
  }
})
await sandbox.context.sayHelloWorld() === 'hello world' // true
await sandbox.context['functions.sayHelloWorld']() === 'hello world' // true

async Sandbox#get(path: Array | string) : any

Get the value of a specific path in the sandbox context.

let sandbox = new Sandbox()
await sandbox.set('obj', {
  hello: 'hello'
, world: 'world'
})
await sandbox.get('obj.hello') === 'hello' // true
await sandbox.get('obj["world"]') === 'world' // true

Equivalent to

let sandbox = new Sandbox()
sandbox.set('obj', {
  hello: 'hello'
, world: 'world'
})
await sandbox.get(['obj', 'hello']) === 'hello' // true
await sandbox.get(['obj', 'world']) === 'world' // true

Equivalent to

let sandbox = new Sandbox()
await sandbox.set('obj', {
  hello: 'hello'
, world: 'world'
})
await sandbox.context.obj.hello === 'hello' // true
await sandbox.context.obj['world'] === 'world' // true

async Sandbox#remove(path: Array | string) : void

Remove the value of a specific path in the sandbox context.

let sandbox = new Sandbox()
await sandbox.set('obj', {
  hello: 'hello'
, world: 'world'
})
await sandbox.remove('obj.hello')
await sandbox.remove('obj["world"]')
await sandbox.context.obj // {}

Equivalent to

let sandbox = new Sandbox()
await sandbox.set('obj', {
  hello: 'hello'
, world: 'world'
})
await sandbox.remove(['obj', 'hello'])
await sandbox.remove(['obj', 'world'])
await sandbox.context.obj // {}

Equivalent to

let sandbox = new Sandbox()
await sandbox.set('obj', {
  hello: 'hello'
, world: 'world'
})
delete sandbox.context.obj.hello
delete sandbox.context.obj.world
await sandbox.context.obj // {}

async Sandbox#call(path: Array | string, ...args: Array) : any

Calling a function within a sandbox context within a specific path, the actual function runs in the sandbox.

let sandbox = new Sandbox()
sandbox.context.helloWorld = 'hello world'
sandbox.context.functions = {}
sandbox.context.functions.sayHelloWorld = function(speaker) {
  return `${ speaker }: ${ helloWorld }`
}
await sandbox.call('functions.sayHelloWorld', 'Sandbox') === 'Sandbox: hello world' // true

Equivalent to

let sandbox = new Sandbox()
sandbox.context.helloWorld = 'hello world'
sandbox.context.functions = {}
sandbox.context.functions.sayHelloWorld = function(speaker) {
  return `${ speaker }: ${ helloWorld }`
}
await sandbox.call(['functions', 'sayHelloWorld'], 'Sandbox') === 'Sandbox: hello world' // true

Equivalent to

let sandbox = new Sandbox()
sandbox.context.helloWorld = 'hello world'
sandbox.context.functions = {}
sandbox.context.functions.sayHelloWorld = function(speaker) {
  return `${ speaker }: ${ helloWorld }`
}
await sandbox.context.functions.sayHelloWorld('Sandbox') === 'Sandbox: hello world' // true

Sandbox#callable : { [string]: Function }

This is an asynchronous Proxy object that can be used as syntactic sugar for Sandbox#registerCall and Sandbox#cancelCall.

let sandbox = new Sandbox()
  , helloWorld = 'hello world'

// Register the Callable function
sandbox.callable.sayHelloWorld = function(speaker) {
  return `${ speaker }: ${ helloWorld }`
}

// Call the Callable function
await sandbox.eval('sayHelloWorld("Sandbox")') === 'Sandbox: hello world' // true

// Cancel registered Callable function
delete sandbox.callable.sayHelloWorld
await sandbox.eval('sayHelloWorld') // ReferenceError!

async Sandbox#registerCall(path: string | Array, func: Function) : void

Register a Callable function in the sandbox, which can be called in the sandbox, but the actual function is done outside the sandbox.

let sandbox = new Sandbox()
  , helloWorld = 'hello world'
await sandbox.registerCall('sayHelloWorld', function(speaker) {
  return `${ speaker }: ${ helloWorld }`
})
await sandbox.eval('sayHelloWorld("Sandbox")') === 'Sandbox: hello world' // true

async Sandbox#cancelCall(path: string | Array) : void

Cancel registered Callable function.

let sandbox = new Sandbox()
  , helloWorld = 'hello world'
await sandbox.registerCall('sayHelloWorld', function(speaker) {
  return `${ speaker }: ${ helloWorld }`
})
await sandbox.cancelCall('sayHelloWorld')
await sandbox.eval('sayHelloWorld')  // ReferenceError!

readonly Sandbox#available : boolean

Used to confirm that the Web Worker within the sandbox is available, and when Sandbox#destroy() is called, its value becomes false.

let sandbox = new Sandbox()
sandbox.available // true

Sandbox#destroy() : boolean

Destroy the Web Worker in the instance of the sandbox, which will call the Worker#terminate () to terminate the Web Worker. If the Web Worker is terminated by this call, it will return true, other cases will return false.

let sandbox = new Sandbox()
sandbox.available // true
sandbox.destroy() // true
sandbox.available // false
sandbox.destroy() // false
sandbox.available // false

class TimeoutError

Use the new operator to create a TimeoutError instance with the constructor parameter consistent with Error.

let err = new TimeoutError('You overtime!')
err instanceof TimeoutError // true
err.message // You overtime!

TimeoutError is only used to detect the exception type using the instanceof operator. Do not create a TimeoutError instance manually.

Tips

The await operator can be omitted when you call Sandbox#set, Sandbox#assign, Sandox#remove, Sandbox#registerCall, Sandbox#cancelCall in the async function. Because the Web Worker inside the sandbox is single-threaded, the asynchronous methods are executed in the order they are called, the await operator is just need added when calling a function that requires a return value.

let sandbox = new Sandbox()
for (let i = 1000; i--;) {
  sandbox.set('hello', 'hello')
  sandbox.assign({
    world: 'world'
  , removable: 'removable'
  })
  sandbox.remove('removable')
}
await sandbox.context.removable === undefined // true
await sandbox.context.hello === 'hello' // true
await sandbox.context.world === 'world' // true

Projects using worker-sandbox

gloria-sandbox: Sandbox for Gloria based on worker-sandbox

Under the hood

The technical principle of the worker-sandbox module is complex and requires a long document to explanation. A detailed description of the technical principles is being written.

worker-sandbox's People

Contributors

blackglory avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.