Skip to content

churchofthought/JSOperations

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

24 Commits
 
 
 
 

Repository files navigation

JSOperations.js

JSOperations is a lightweight library for queueing operations. It provides a JSOperationsQueue with a maxConcurrentOperationCount property to limit the number of tasks running at a single time. Operations can be suspended, cancelled, and can have a queuePriority set, which will determine the order in which they execute.

Here's a quick example of what JSOperations does: Calculating fibonacci for n=500 would normally freeze the UI. But if we write an operation that suspends itself, the queue will automatically resume it on the next paint cycle.

var queue = new JSOperationQueue();

var fib = new JSAsyncBlockOperation(function(op, blk){
	this.results.push(this.results[0] + this.results[1]);
	this.results.shift();

	if (++this.i >= 500) op.finish();
	else op.suspend();
  
}, {i: 1, results:[0,1]});
fib.resumptionBlock(fib.executionBlock()); // fib should resume at its execution block

fib.completionBlock(function(op){
	console.log("fib of " + this.i + " is " + this.results.pop());
}, fib.context());

queue.addOperation(fib);

When an operation is resumed, its resumptionBlock is called. That is utilized in the above example.

There are 4 related blocks you can set on an operation: suspensionBlock, resumptionBlock, cancellationBlock, and completionBlock

Because javascript code cannot be 'terminated', it is your job to set these blocks if you desire your operation to be re-entrant / terminatable. In the above example, we don't need to set a suspensionBlock because there are no resources like lingering ajax requests to cancel.

Dependencies

Operations can also have dependencies. Let's say you need to get some json data from 2 seperate ajax requests and do something only when both requests have returned. Here's what you can do:

var queue = new JSOperationQueue();

var req1 = new JSAsyncBlockOperation(function(op, blk){
   $.get('data1', function(data){
      blk.context().data1 = data;
      op.finish();
   });
}, {});

var req2 = new JSAsyncBlockOperation(function(op, blk){
   $.get('data2', function(data){
      blk.context().data2 = data;
      op.finish();
   });
}, req1.context());

var resOp = new JSBlockOperation(function(op, blk){
    console.log("data1:", this.data1);
    console.log("data2:", this.data2);
}, req1.context());

resOp.dependencies([req1, req2]);

queue.addOperations(req1, req2, resOp);

Dependencies can be much more complex and intertwined, the above is just a simple example.

Cancelling Operations

Operations can be cancelled by calling operation.cancel()

To cancel all operations from a queue, simply call queue.cancelAllOperations()

Operations should free up lingering ajax requests, and other resources when cancelled. In order to respond to a cancellation, be sure to set a cancellationBlock for any operations you create.

Custom Operations

JSOperation is the main operation class. To write a custom operation, inherit from JSOperation and override main(), the main execution function for an operation. If your operation is not over when main() returns, you should override isConcurrent to return true. When your operation is done, call operation.finish() to let the queue, and other observers know that your operation is over.

There are 2 classes to make concurrent and non-concurrent operations without subclassing. These are JSBlockOperation and JSAsyncBlockOperation.

About

A port of NSOperationQueue from Cocoa, to the web

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published