0.7.1 • Published 7 years ago

@checle/zones v0.7.1

Weekly downloads
1
License
MIT
Repository
github
Last release
7 years ago

zones

by Filip Dalüge

Build status

For a primer on zones in Dart, take a look at the Dart article. Find the complete API here.

Installation

Install using NPM:

npm install --save web-zones

Import zones:

import * as zones from 'web-zones'

Object.assign(global, zones) // Optionally, shim the host API (overrides setTimeout, Promise etc.)

Usage

Wait for operations spawned by a function

await zone.exec(initAppFunction)

Listen to state

zone.addEventListener('error', listener)

Cancel pending operations

zone.cancel()

Bind function

func = zone.bind(func)

Number of scheduled tasks

zone.tasks.size

Examples

Instantiate a zone and listen for events

Create a zone object and listen for status events.

var zone = new Zone('custom-zone')

zone.addEventListener('finish', () => console.log('Zone has terminated'))
zone.addEventListener('error', error => console.log('Error occurred'))

function application () {
  setTimeout(() => null, 1000)
}

zone.run(application)

Asynchronous operations

Run an application that reads a file making use of asynchronous JS APIs. The result is then awaited, and its content printed.

import * as fs from 'fs'

// Application with unknown asynchronous operations
function application() {
  // Waits for a second
  setTimeout(readFile, 1000)

  function readFile () {
    // Read asynchronously
    fs.readFile('data.txt', data => {
      global.fileContent = data
    })
  }
}

try {
  // Call and wait for spawned tasks to terminate
  await global.zone.exec(application)

  console.log('This file content has been read: ' + global.fileContent)
} catch (error) {
  console.log('Either setTimeout or fs.readFile threw an uncatched error')
}

Execute tasks parallely

Run three processes using Promise.all and wait for them to finish. Cancel any other zones if one zone throws an error.

try {
  await Promise.all([
    zone.exec(app1),
    zone.exec(app2),
    zone.exec(app3),
  ])

  console.log('All tasks have concluded successfully')
} catch (error) {
  console.log('One zone errored:', error.zone.name)

  // Cancel all remaining zones
  zone.cancel()
}

Extend zones

Add custom properties to zone by inheritance.

class CustomEnvironment extends Zone {
  constructor () {
    super('custom-environment')

    this.created = Date.now()
  }
}

function routine () {
  if (global.zone instanceof CustomEnvironment) {
    console.log('My environment was created at ' + global.zone.created)
  } else {
    console.log("I think I've been running forever")
  }
}

global.zone.run(routine) // "I think I've been running forever"

new CustomEnvironment().run(routine) // Prints the creation date

Override enter()

You can hook into zone operations overriding enter().

let lastDomain

class MozillaZone extends Zone {
  enter (zone) {
    if (zone instanceof MozillaZone) {
      lastDomain = global.domain
      global.domain = 'mozilla.org'
    } else {
      global.domain = lastDomain
    }

    super.enter(zone)
  }
}

global.domain = 'example.com'

new MozillaZone().run(() => console.log(global.domain)) // "mozilla.org"

global.zone.run(() => console.log(global.domain)) // "example.com"

Run untrusted code asynchronously

Run code in a sandbox using NodeJS' vm module and print the result.

const vm = require('vm')

// Create sandbox
let sandbox = {
  setTimeout,
  setInterval,
  setImmediate,
  print: console.log
}

let applicationCode = `
  if (typeof console !== 'undefined') {
    console.log("I'm not that secure, it seems.")
  } else {
    print('Oh yes, I am.')
  }
`

try {
  // Use exec with vm to run a program in an isolated environment
  let result = await zone.exec(() => vm.runInNewContext(applicationCode, sandbox))

  console.log('Terminated successfully with result', result)
} catch (error) {
  console.log('An error occurred')
)

API

zone: Zone // Get the current zone

interface Task extends Event {
  cancel?: Function
}

interface Zone extends EventTarget, Node {
  onerror?: Function // Set 'error' event handler
  onfinish?: Function // Set 'finish' event handler

  readonly name: any // Optional name, e.g., for debugging
  readonly tasks: Map<any, Task> // Pending tasks
  readonly children: Zone[] // Associated children, modifiable by the DOM
  readonly root: Zone // Root zone - all error events bubble towards this zone

  constructor (nameOrSpec?: any)

  // Add and manage custom tasks
  addTask (task: Task): number
  setTask (id: any, task: Task): this
  getTask (id: any): Task
  hasTask (id: any): boolean
  removeTask (id: any): boolean
  cancelTask (id: any): Promise<void>

  // Run function inside zone
  run (entry: Function, thisArg?: any, ...args: any[]): any
  // Bind function to zone
  bind (fn: Function): Function
  // Cancels all child zones and pending tasks
  cancel (): Promise<void> 
  // Spawns a new child zone, runs `entry` in it and resolves when all new tasks have been worked off
  exec (entry: Function, thisArg?: any, ...args: any[]): Promise<any>

  // Add event listeners
  addEventListener (type: 'finish' | 'error', listener: Function, options: any): void
  // Modify the DOM - affects which children will be cancelled on `cancel()` and where 'error' events will bubble to
  appendChild (node: Zone): this
}

// Zone-enabled standard API
function setTimeout (handler, timeout, ...args)
function setInterval (handler, timeout, ...args)
function clearTimeout (id)
function clearInterval (id)
function Promise (executor)

License

MIT © 2016 Filip Dalüge (license)