<!DOCTYPE html> <html lang='en'> <head> <meta charset='utf-8'> <title>synchronize.js</title> <meta name='viewport' content='width=device-width, initial-scale=1.0'> <meta name='description' content=''> <meta name='author' content=''> <!-- Styles --> <link href='assets/bootstrap/css/bootstrap.css' rel='stylesheet'> <link href='assets/google-code-prettify/prettify.css' rel='stylesheet'> <link href='assets/style.css' rel='stylesheet'> <!-- HTML5 shim, for IE6-8 support of HTML5 elements --> <!--[if lt IE 9]> <script src='http://html5shim.googlecode.com/svn/trunk/html5.js'></script> <![endif]--> </head> <body> <!-- <div class='navbar navbar-fixed-top'> <div class='navbar-inner'> <div class='container'> <a class='brand' href='#'>synchronize.js</a> <ul class='nav'> <li class='active'><a href='#'>Home</a></li> <li><a href='#about'>About</a></li> <li><a href='#contact'>Contact</a></li> </ul> </div> </div> </div> --> <div class='container'> <!-- <pre class='prettyprint'> a = function(){ console.log('hi') } </pre> --> <div class='row'> <div class='offset1 span10'> <!-- Overview --> <div class='page-header'> <h1> synchronize.js <small>write asynchronous code as if it's synchronous</small> </h1> </div> <p> Use <code>await</code> and <code>defer</code> to execute asynchronous functions synchronously. </p> <p> Synchronize assumes node-style <code>(err, result)</code> callbacks. The second parameter given to the cb will be returned. If an error is present it will be thrown and can be intercepted by a try/catch statement. Multiple and named arguments are supported with <code>defers</code>. </p> <p> You can use the helper <code>sync(fn)</code> and it will use await/defer automatically. The helper is non-destructive and the function can still be called asynchronously if called with a callback. You can also mix it with other synchronous or asynchronous code. </p> <p> Use <code>await</code>/<code>defer</code> manually to get precise control or automatically to write compact and clean code. </p> <p> Install it with <code>npm install synchronize</code>. </p> <p> The project is hosted on <a href='http://github.com/alexeypetrushin/synchronize'>GitHub</a>. <br> You can report bugs and discuss features on the <a href='http://github.com/alexeypetrushin/synchronize/issues'>Issues</a> page. </p> <!-- How to use --> <h2>Usage patterns</h2> <div class='row'> <div class='span5'> <pre class='prettyprint'> data = sync.await(fs.readFile(fname, sync.defer())) </pre> </div> <div class='span5'> <p> Use <code>await</code> and <code>defer</code> keywords by hand to call a function synchronously (you can make await and defer global to make things shorter). </p> </div> </div> <div class='row' style="margin-top: 10px"> <div class='span5'> <pre class='prettyprint'> sync(fs, 'readFile') var data = fs.readFile(fname) fs.readFile(fname, function(err, data)){} </pre> </div> <div class='span5'> <p> Use <code>sync()</code> to make an async function synchronize.js-aware. You can use it in both ways - synchronous or asynchronous. Basically it uses the same await/defer pattern, but automatically. This object form preserves context, unlike the form below. </p> </div> </div> <div class='row' style="margin-top: 10px"> <div class='span5'> <pre class='prettyprint'> asyncFn = sync(asyncFn) var data = asyncFn(input) // You can still use the async form of this fn var data = sync.await(asyncFn(input, sync.defer())) asyncFn(input, function(err, data){}) </pre> </div> <div class='span5'> <p> You can use <code>sync()</code> on a bare function to return a synchronized version of the function. It can still be used in asynchronous form. </p> </div> </div> <!-- Samples --> <h2>Basic usage, printing content of file</h2> <div class='row'> <div class='span5'> <pre class='prettyprint'> var sync = require('synchronize') var fs = require('fs') sync(fs, 'readFile') sync.fiber(function(){ var data = fs.readFile(__filename, 'utf8') console.log(data) try { data = fs.readFile('invalid', 'utf8') } catch (err) { console.log(err) } fs.readFile(__filename, 'utf8', function(err, data){ console.log(data) }) }) </pre> </div> <div class='span5'> <p> In order to use synchronized functions and pause execution without blocking Node.js we need to wrap execution into a <code>Fiber</code> using <code>sync.fiber()</code>. </p> <p style="margin-top:50px"> Inside of Fiber we can call asynchronous functions as if it's synchronous. </p> <p style="margin-top:30px"> We can also use standard try/catch statements to catch asynchronous errors. </p> <p style="margin-top:70px"> Or call readFile asynchronously if we wish. </p> </div> </div> <h2>Listing and printing files in directory</h2> <p> Listing content of current directory, checking if path is file and printing its content to console. </p> <div class='row'> <div class='span5'> <h3>Using synchronize</h3> <pre class='prettyprint'> var sync = require('synchronize') var fs = require('fs') sync(fs, 'readdir', 'stat', 'readFile') sync.fiber(function(){ var i, paths, path, stat, data paths = fs.readdir('.') for(i = 0; i < paths.length; i++){ path = paths[i] stat = fs.stat(path) if(!stat.isFile()) continue data = fs.readFile(path, 'utf8') console.log(data) } }) </pre> </div> <div class='span5'> <h3>The same code without synchronization</h3> <pre class='prettyprint'> var fs = require('fs') var printFile = function(paths, i){ if(i >= paths.length) return var path = paths[i] fs.stat(path, function(err, stat){ if(err) throw err if(stat.isFile()){ fs.readFile(path, 'utf8', function(err, data){ if(err) throw err console.log(data) printFile(paths, i + 1) }) } else { printFile(paths, i + 1) } }) } fs.readdir('.', function(err, paths){ if(err) throw err printFile(paths, 0) }) </pre> </div> </div> <h2>Parallel and serial operations</h2> <p> Synchronize.js can run multiple operations in parallel using <code>sync.parallel()</code>. </p> <div class='row'> <div class='span5'> <h3>Async operations in serial</h3> <pre class='prettyprint'> var sync = require('synchronize') var read = function(a, cb) { setTimeout(function(){ // remember that callbacks expect (err, result) cb(null, a) }, 1000) } // We can use the `sync` helper here to avoid using // `await()` and `defer()` manually. read = sync(read); sync.fiber(function() { var results = [] results.push(read(1))) results.push(read(2))) // results now contains [1,2] }) </pre> </div> <div class='span5'> <h3>Async operations in parallel</h3> <pre class='prettyprint'> var sync = require('synchronize') function read(a, cb) { setTimeout(function(){ cb(null, a) }, 1000) } // Runs in parallel sync.fiber(function() { sync.parallel(function() { // You must call defer() manually within // a parallel operation. read(1, sync.defer()) read(2, sync.defer()) }); var results = sync.await() // results now contains [1,2] }); </pre> </div> </div> <h2>Multiple arguments in callbacks</h2> <p> Synchronize.js accepts multiple arguments in callbacks using <code>sync.defers()</code>. </p> <div class='row'> <div class='span5'> <h3>Multiple arguments in serial</h3> <pre class='prettyprint'> var sync = require('synchronize') function read(a, b, c, cb) { setTimeout(function(){ cb(null, a, b, c) }, 1000) } sync.fiber(function() { // Returns [1,2,3] var results = sync.await( read(1, 2, 3, sync.defers())) // Returns {a: 4, b: 5, c: 6} var namedResults = sync.await( read(4, 5, 6, sync.defers('a', 'b', 'c'))) }) </pre> </div> <div class='span5'> <h3>Multiple arguments in parallel</h3> <pre class='prettyprint'> var sync = require('synchronize') function read(a, b, c, cb) { setTimeout(function(){ cb(null, a, b, c) }, 1000) } sync.fiber(function() { sync.parallel(function(){ read(1, 2, 3, sync.defers()) read(4, 5, 6, sync.defers()) }); // returns [[1,2,3],[4,5,6]] var results = sync.await() // concat to get [1,2,3,4,5,6] results = [].concat.apply([], results) }) </pre> </div> </div> <h2>Usage with Express.js</h2> <div class='row'> <div class='span5'> <pre class='prettyprint'> var sync = require('synchronize') var fs = require('fs') var express = require('express') sync(fs, 'readFile') var app = express.createServer() app.use(function(req, res, next){ sync.fiber(next) }) app.get('/', function(req, res){ var data = fs.readFile(__filename, 'utf8') res.send(data, {'Content-Type': 'text/plain'}) }) app.listen(3000) </pre> </div> <div class='span5'> <p>Synchronized code can be mixed with asynchronous code in any combination.</p> <p> Here is one possible way to use it with Express.js.</p> </div> </div> <h2>Usage with Mocha.js</h2> <div class='row'> <div class='span5'> <pre class='prettyprint'> var sync = require('synchronize') var fs = require('fs') sync(fs, 'readFile') var async = sync.asyncIt describe('File System', function(){ it('should read file', async(function(){ var data = fs.readFile(__filename, 'utf8') })) }) </pre> </div> <div class='span5'> <p> You can use the <code>sync.asyncIt</code> helper to greatly simplify writing asynchronous tests. </p> <p> You may also take a look at <a href='https://github.com/alexeypetrushin/mongo-lite/blob/master/test/collection.coffee'> this real-life test scenario</a> that uses synchronize to simplify asynchronous calls for MongoDB. </p> </div> </div> <!-- How to use --> <h2>Similar tools</h2> <p> <a href="http://monojs.org">MonoJS</a> - synchronous web framework based on synchronize. </p> <hr/> <p>Copyright <a href='http://petrush.in'>Alexey Petrushin</a>, released under MIT License</p> </div> </div> </div><!-- /container --> <a href='http://github.com/alexeypetrushin/synchronize'><img style='position: absolute; top: 0; right: 0; border: 0; z-index: 2080;' src='https://s3.amazonaws.com/github/ribbons/forkme_right_gray_6d6d6d.png' alt='Fork me on GitHub'></a> <!-- Scripts --> <script src='https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'></script> <script src='assets/bootstrap/js/bootstrap.js'></script> <script src='assets/google-code-prettify/prettify.js'></script> <script> $(prettyPrint) </script> </body> </html>