npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

exec.js

v1.6.0

Published

A low latency javascript code runner that enables to isolate and abort javascript code execution, including setTimeout/setInterval, promises and Fetch requests. It supports all browsers.

Downloads

36

Readme

Javascript Code Runner npm version

exec.js (922 bytes) is a low latency javascript code runner that enables to isolate and abort javascript code execution, including setTimeout/setInterval, promises and Fetch requests. It supports all browsers.

The code is executed in an isolated container with fine grained restriction capabilities, access to DOM and the ability to return functions and objects without serialization or cloning.

For some workloads, the javascript performance appears to be better than a WebWorker in modern browsers, without blocking UI (see tests). The startup latency can be reduced to <1ms compared to ~100ms for a WebWorker (2018).

In future versions of Chrome exec.js may be executed in a separate thread (multi-threading), offering an advantage over Web Workers. For more information, see Out-of-Process iframes (OOPIFs).

Table of contents

Install

with npm:

npm install exec.js

with bower:

bower install exec.js

Usage

Include exec.js in the HTML document.

<script src="exec.min.js"></script>

Use var runner = new exec(code[, onmessage][, sandbox][, csp]); to execute javascript code in an isolated container. You can provide the code as a string or as a function.

// start code runner with onmessage callback
var runner = new exec('setInterval(function() {console.log("startup code")},200);onmessage=function(data){console.log("UI sent",data);};', 
    function onmessage(data) {
        console.info('response from container:', data);
    });

// start code runner with security isolation
// var runner = new exec('console.log("secured code");',null,['allow-pointer-lock'],{"default-src": "domain.com","script-src":"'sha256-076c8f1ca6979ef156b510a121b69b6265011597557ca2971db5ad5a2743545f'"});

// execute code in container
runner.exec('console.log("some code");');

// redefine onmessage callback
runner.on(function message(data) {
    console.info('response from container (redefined)',data);
});

// post data to container
runner.post('some data');

// execute code in container
runner.exec(function(postMessage) {

    // reconfigure message handler
    onmessage = function(data) {
        postMessage("received " + data + " in container");
    }
});

// execute code in container
runner.exec(function(postMessage) {

    // reconfigure message handler to process functions
    onmessage = function(fn) {

        fn(); // function passed from UI

        // pass a function back to UI
        postMessage(function(x,y,z) { /* ... */ });
    }
});

// post function to container
runner.post(function() { console.log('test OK'); });

// stop code execution
runner.stop(); // this will abruptly stop any code execution including unfinished promises

// chain
new exec('onmessage=function(data){console.log(data);}',null,['allow-pointer-lock'])
    .post('test 1')
    .post('test 2')
    .on(function message(data) {
        console.info('response from container:',data);
    })
    .exec('console.log("test 3");')
    .exec(function(postMessage){postMessage("post to UI");})
    .stop();

You can return data from your code using the postMessage(data) function. You can receive data in the container by defining onmessage=function(e) { // e.data } in the container.

Simple Fetch request

var runner = new exec(function(postMessage) {

    fetch('https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js')
        .then(postMessage)
        .catch(function(err) {
            console.log(err.message);
        });

}, function(response) {

    // process fetch response    
    response.text().then(function(text) {
        console.log('fetch result', text.length);
    });
    
});

// timeout in 5 seconds
setTimeout(function() {
    runner.stop(); // cancel Fetch request
},5000);

Abortable Fetch

Include exec-fetch.js (221 bytes) in the HTML document.

<script src="exec.min.js"></script>
<script src="exec-fetch.min.js"></script>

The native fetch API is now enhanced with a .abort() method. This is not a Polyfill.

// normal fetch request
var request = fetch('https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js')
    .then(function(response) {
        response.text().then(function(text) {
            console.log('response', text.length);
        });
    }).catch(function(err) {
        console.log('err', err.message);
    });

// abort request after 10ms
setTimeout(function() {
    request.abort();
}, 10);

Fine tune the timeout to test Fetch request and/or response cancellation.

Cancelled Fetch API Request and Response

Abortable fetch requires a dedicated exec.js container per fetch request. Use a container pool to improve performance.

Performance

Enhance the performance of exec.js when making subsequent/simultaneous requests by creating a container pool. Code isolation can be applied as a third parameter.

// create container pool for performance
exec(5);

// exec(5,null,[]); // pool with code isolation enabled

console.time('abortable fetch with pool');
var url = 'https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js';
fetch(url).catch(function(err){}).abort();
fetch(url).catch(function(err){}).abort();
fetch(url).catch(function(err){}).abort();
fetch(url).catch(function(err){}).abort();
fetch(url).catch(function(err){}).abort();
console.timeEnd('abortable fetch with pool');

Abort / cancel code execution

To cancel code execution, use runner.stop().

var runner = new exec('setInterval(function() {console.log(123);},100);');
setTimeout(function() {
    runner.stop();
},1000);

Access to DOM

To access the DOM, use parent.document (info). DOM access is available in all browsers.

var runner = new exec('setInterval(function() {var h = parent.document.createElement(\'h1\');h.innerHTML = \'test\';parent.document.body.insertBefore(h, parent.document.body.firstChild);},100);');
setTimeout(function() {
    runner.stop();
},1000);

Security / code isolation

It is possible to isolate the code to be executed and block access to DOM, navigation, popups, form submission and other specific privileges by passing a third parameter with an array of sandbox parameters and/or a fourth parameter with Content-Security-Policy (CSP) configuration.

// enable code isolation
new exec(code,onmessage,[])

// enable code isolation with forms and API's enabled
new exec(code,null,['allow-forms','allow-pointer-lock']);

// enable code isolation and block loading of images, objects and media
new exec(code,null,[],{"img-src":"'none'","media-src":"'none'","object-src":"'none'"});

// restrict resource access to domain without code isolation
new exec(function(){
    // test CSP using Fetch
    fetch('https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js').catch(function(err) {});
},null,null,{"default-src":"domain.com"});

Code isolation is disabled by default. When enabled, the allow-scripts and allow-same-origin sandbox parameters are enabled by default.

Content Security Policy (CSP) Whitelist

To whitelist exec.js add script-src 'nonce-execjs' to the Content-Security-Policy. To use the runner.exec() method, script-src: 'unsafe-eval' is required.