Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Before reading this please ensure you fully understand the concept of Web Workers.
Operative is a small JS utility (~1.8k gzipped) for seamlessly creating Web Worker scripts. Its features include:
console
interface for simple loggingUtilising unabstracted Workers can be cumbersome and awkward. Having to design and implement message-passing contracts and having to setup event listeners yourself is time-consuming and error-prone. Operative takes care of this stuff so you can focus on your code.
Even with Operative you are still subject to the constraints of Web Workers, i.e.
And it won't make things uniformly faster or less burdensome on the UI. Operative will fall-back to using iframes in older browsers, which gives you no non-blocking advantage.
Non-blob worker support (i.e. for IE10) requires that you have a same-origin copy of Operative (this means you can't solely rely on CDNs or elsewhere-hosted scripts if you want to support IE10).
Operative 0.4.4
has been explicitly tested in:
Support for Workers, with varying degrees of support for Transferables and Blobs:
Note: Operative has not been tested in non-browser envs
# bower
bower install operative
# or npm
npm install operative
Or just grab the built JS file from dist/
, also available here (0.4.4):
An Operative module is defined as an object containing properties/methods:
var calculator = operative({
add: function(a, b, callback) {
callback( a + b );
}
});
This would expose an asynchronous API:
calculator.add(1, 2, function(result) {
result; // => 3
});
The add()
function will run within a worker. The value it returns is handled by operative and forwarded, asynchronously to your callback function in the parent page.
Notice that the exposed add
method requires its last argument to be a callback. The last argument passed to an operative method must always be a callback. All preceding arguments are passed into the worker itself.
NOTE: It's important to note that the Operative code is not executed in-place. *It's executed within a Worker. You won't be able to access variables surrounding the definition of your operative:
// THIS WILL NOT WORK!
var something = 123;
var myWorker = operative({
doStuff: function() {
something += 456;
}
});
(the something variable won't exist within the Worker)
Instead you can do:
var myWorker = operative({
something: 123,
doStuff: function() {
this.something += 456;
}
});
var craziness = operative({
doCrazy: function(cb) {
console.time('Craziness');
for (var i = 0; i < 10000000000; ++i);
console.timeEnd('Craziness');
cb('I am done!');
}
});
craziness.doCrazy(function(result) {
// Console outputs: Craziness: 14806.419ms
result; // => "I am done!"
});
Operative degrades in this order:
(higher is better/cooler)
Operative will degrade in environments with no Worker or Blob support. In such a case the code would execute as regular in-place JavaScript. The calls will still be asynchronous though, not immediate.
If you are looking to support this fully degraded state (honestly, only do it if you have to) then you'll also need to avoid utilising Worker-specific APIs like importScripts
.
Operative supports browsers with no worker-via-blob support (e.g. IE10, Safari 4.0) via eval, and it requires operative.js
or operative.min.js
to be its own file and included in the page via a <script>
tag. This file must be on the same origin as the parent page.
If you're bundling Operative with other JS, you'll have to have an additional (same-origin!) operative.js
and specify it before creating an operative module via operative.setSelfURL('path/to/operative.js')
(this'll only generate a request where the aforementioned support is lacking). Due to the usage of eval in these cases it is recommended to debug your operatives in more capable browsers.
JSON.stringify
.operative({ method: function() {...} ... });
operative(function() {})
(in which case a single function is returned)operative(..., ['dep1.js', 'dep2.js'])
.<script src="operative.js"></script>
.To create an operative module pass an object of methods/properties:
var myOperative = operative({
doX: function(a, b, c, callback) {
// ...
},
doY: function(a, b, c, callback) {
// ...
}
});
Or a single function to create a singular operative:
var myOperative = operative(function(a, b, c, callback) {
// Send the result to the parent page:
callback(...);
});
// Example call:
myOperative(1, 2, 3, function() { /*callback*/ });
The most simple way to use operative is to pass in a callback function when calling an operative function and within the operative method call the callback with your result:
var combine = operative(function(foo, bar, callback) {
callback(foo + bar);
});
combine('foo', 'bar', function() {
// This callback function will be called with
// the result from your operative function.
result; // => 'foobar'
});
If you don't pass a callback when calling an operative method, operative will assume you want a Promise. Note that operative will reference operative.Promise
and will expect it to be a native Promise implementation or compliant polyfill. Operative does not come bundled with a Promise implementation.
var combine = operative(function(foo, bar) {
// Internally, use a Deferred:
var deferred = this.deferred();
// A deferred has two methods: fulfill & reject:
if (foo !== 'foo') {
// Error (Rejection)
deferred.reject('foo should be "foo"!');
} else {
// Success (Filfillment)
deferred.fulfill(foo + bar);
}
});
// Usage externally:
var promise = combine('foo', 'bar');
promise.then(function(value) {
// Fulfilled
}, function(err) {
// Rejected
});
NOTE: Operative will only give you a promise if you don't pass a callback and if operative.Promise
is defined. By default operative.Promise
will reference window.Promise
(native implementation if it exists).
Operative accepts a second argument, an array of JS files to load within the worker ( or in its degraded state, an Iframe ):
// Create interface to call lodash methods inside a worker:
var lodashWorker = operative(function(method, args, cb) {
cb(
_[method].apply(_, args)
);
}, [
'http://cdnjs.cloudflare.com/ajax/libs/lodash.js/1.3.1/lodash.min.js'
]);
lodashWorker('uniq', [[1, 2, 3, 3, 2, 1, 4, 3, 2]], function(output) {
output; // => [1, 2, 3, 4]
});
Declared dependencies will be loaded before any of your operative's methods are called. Even if you call one from the outside, that call will be queued until the context (Worker/iFrame) completes loading the dependencies.
Note: Each dependency, if not an absolute URL, will be loaded relative to the calculated base URL, which operative determines like so:
var baseURL = (
location.protocol + '//' +
location.hostname +
(location.port?':'+location.port:'') +
location.pathname
).replace(/[^\/]+$/, '');
To override at runtime use:
operative.setBaseURL('http://some.com/new/absolute/base/');
// Ensure it ends in a '/'
// To retrieve the current Base URL:
operative.getBaseURL();
To terminate the operative (and thus its worker/iframe):
o.terminate();
(terminate
is aliased to the now-deprecated destroy
)
Special thanks to BrowserStack for providing free testing!
$ # grab dependencies
$ npm install
$ # install grunt globally if you don't have it...
$ npm install -g grunt-cli
$ # test
$ grunt test
$ # do everything + build dist:
$ grunt
Error
obj issue (see #44 & #45)Uncaught ReferenceError: hasTransferSupport is not defined
(see #43)async()
method in favor of callbacks or promisesmocha_phantomjs
to setup mocha testing via gruntdeferred.fulfil()
(worker context promise API) in favour of deferred.resolve()
(alias for fulfil
still exists).terminate
aliased to destroy
(deprecating the latter). See Issue #14.operative(Function)
which returns a single function.this.async()
).FAQs
Operative: Inline Web-Worker Helper
We found that operative demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.