• Stars
    star
    240
  • Rank 162,004 (Top 4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created over 13 years ago
  • Updated about 8 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A JavaScript library for communicating asynchronously with remote objects using promises.

Build Status

Asynchronous Remote Objects

This library makes it possible for objects to communicate asynchronously between memory-isolated JavaScript contexts, including pipelining interactions with results. Promises serve as proxies for remote objects.

Q-Connection works in Node and other CommonJS module loaders like Browserify, Mr, and Montage.

This is how it looks:

var Q = require("q");
var Connection = require("q-connection");
var remote = Connection(port, local);

The remote object is a promise for the local object on the other side of the connection. Likewise, the other side of the connection will get a promise for your local object. You are not obliged to provide a local object, depending on which end of the connection is providing a service.

If the remote or local object is not serializable, like functions or objects with methods, the other side will receive a promise but you will have to “send messages” to the promise instead of interacting directly with the remote object. When you invoke a method on a remote object, you get a promise for the result and you can immediately pipeline a method call on the result. This is the secret sauce.

The port is any W3C message port, web worker, or web socket. In the W3C’s infinite wisdom, these do not have a unified API, but Q-Connection will normalize them internally.

// To communicate with objects in a worker
var worker = new Worker("worker.js");
var child = Connection(worker, local);
// Inside a worker, to communicate with the parent
var parent = Connection(this);
// To communicate with a remote object on the other side of
// a web socket
var socket = new WebSocket("ws://example.com");
var remote = Connection(socket, local);
// To communicate with a single frame on the same origin
// (multiple frames will require some handshaking event sources)
var iframe = document.frames[0];
var child = Connection(iframe.contentWindow, local, {
    origin: window.location.origin
})
// To communicate with a parent frame on the same origin
var child = Connection(window, local, {
    origin: window.location.origin
})
// With a message port
var port = new MessagePort();
var near = Connection(port[0]);
var far = Connection(port[1]);

Your local value can be any JavaScript value, but it is most handy for it to be an object that supports an API and cannot be serialized with JSON.

var Q = require("q");
var counter = 0;
var local = {
    "next": function () {
        return counter++;
    }
};

In this case, the local object has a "next" function that returns incremental values. Since the function closes on local state (the counter), it can't be sent to another process.

On the other side of the connection, we can asynchronously call the remote method and receive a promise for the result.

remote.invoke("next")
.then(function (id) {
    console.log("counter at", i);
});

The connection is bi-directional. Although you do not need to provide and use both local and remote values on both sides of a connection, they are available.

You can asynchronously interact with any value using the Q API. This chart shows the analogous operations for interacting with objects synchronously and asynchronously.

synchronous                asynchronous
------------------         -------------------------------
value.foo                  promise.get("foo")
value.foo = value          promise.put("foo", value)
delete value.foo           promise.del("foo")
value.foo(...args)         promise.post("foo", [args])
value.foo(...args)         promise.invoke("foo", ...args)
value(...args)             promise.fapply([args])
value(...args)             promise.fcall(...args)

All of the asynchronous functions return promises for the eventual result. For the asynchronous functions, the value may be any value including local values, local promises, and remote promises.

The benefit to using the asynchronous API when interacting with remote objects is that you can send chains of messages to the promises that the connection makes. That is, you can call the method of a promise that has not yet been resolved, so that message can be immediately sent over the wire to the remote object. This reduces the latency of interaction with remote objects by removing network round-trips.

A chain of dependent operations can be contracted from:

<-client     server->
a..
   ''--..
         ''--..
               ''--..
             ..--''
       ..--''
 ..--''
b..
   ''--..
         ''--..
               ''--..
             ..--''
       ..--''
 ..--''
c..
   ''--..
         ''--..
               ''--..
             ..--''
       ..--''
 ..--''

Down to:

<-client     server->
a..
b..''--..
c..''--..''--..
   ''--..''--..''--..
         ''--..--''..
       ..--''..--''..
 ..--''..--''..--''
 ..--''..--''
 ..--''

Where the dotted lines represent messages traveling through the network horizontally, and through time vertically.

Ports

Q-Connection handles a variety of message ports or channel types. They are all internally converted into a Q Channel. If you are using a message channel that provides a different API than this or a WebWorker, WebSocket, or MessagePort, you can adapt it to any of these interfaces and Q-Connection will handle it.

This is probably the simplest way to create a channel duck-type, assuming that you’ve got a connection instance of the Node variety.

var port = {
    postMessage: function (message) {
        connection.send(message);
    },
    onmessage: null // gets filled in by Q-Connection
};
connection.on("message", function (data) {
    port.onmessage({data: ""})
});
var remote = Connection(port, local);

Here's an example showing adapting socket.io to the message port.

var port = {
  postMessage: function (message) {
    socket.emit("message", message);
  },
  onmessage: null // gets filled in by Q-Connection
};
socket.on("message", function(data) {
  port.onmessage({data: data});
});
var remote = Connection(port, local);

Q Channels

  • get() returns a promise for the next message from the other side of the connection. get may be called any number of times independent of when messages are actually received and each call will get a promise for the next message in sequence.
  • put(message) sends a message to the remote side of the connection.
  • close(reason_opt) indicates that no further messages will be sent.
  • closed a promise that is fulfilled with the reason for closing.

Q-Connection exports an indefinite Queue that supports this API which greatly simplifies the implementation of adapters.

  • get() returns a promise for the next value in order that is put on the queue. get may be called any number of times, regardless of whether the corresponding value is put on the queue before or after the get call.
  • put(value) puts a message on the queue. Any number of messages can be put on the queue, indepent of whether and when the corresponding get is called.
  • close(reason_opt) indicates that no further messages will be put on the queue and that any promises for such messages must be rejected with the given reason.
  • closed a promise that is fulfilled when and if the queue has been closed.

Web Workers and Message Ports

Q-Connection detects ports by their postMessage function.

  • postMessage(message)
  • onmessage(handler(message))

Web Sockets

Q-Connection detects Web Sockets by their send function. It takes the liberty to start the socket and listens for when it opens.

  • send(message)
  • addEventListener(event, handler(event))
  • start()
  • open event
  • close event

Memory

Q-Connection uses an LRU cache of specified size. The default size is infinite, which is horribly leaky. Promises between peers will stick around indefinitely. This can be trimmed to something reasonable with the max option.

var remote = Connection(port, local, {max: 1024});

The least frequently used promises will be collected. If the remote attempts to communicate with a collected promise, the request will be ignored. The minimum working set will vary depending on the load on your service.

To be notified when communication is attempted with a collected promise set the onmessagelost option.

var remote = Connection(port, local, {
    max: 1024,
    onmessagelost: function (message) {
        console.log("Message to unknown promise", message);
    }
});

More Repositories

1

q

A promise library for JavaScript
JavaScript
14,957
star
2

gtor

A General Theory of Reactivity
JavaScript
3,004
star
3

asap

High-priority task queue for Node.js and browsers
JavaScript
604
star
4

q-io

Interfaces for IO using Q promises in JavaScript on Node
JavaScript
315
star
5

uncommonjs

Uncommonly designed JavaScript specifications
JavaScript
172
star
6

zip

An implementation of unzip in JavaScript for Node
JavaScript
85
star
7

tengwarjs

A Tengwar (J.R.R. Tolkien’s Elvish alphabet) transcriber for ES5 and HTML5
JavaScript
55
star
8

util

Out of service, use Collections — The missing methods of JavaScript
JavaScript
44
star
9

context

JavaScript context cancellation, deadlines, storage
JavaScript
43
star
10

collections

JavaScript collections with idiomatic interfaces
JavaScript
33
star
11

3rin.gs

An online map of Middle Earth
HTML
30
star
12

chiron

Missing types and methods for JavaScript
JavaScript
28
star
13

narwhal-lib

Narwhal's pure-JavaScript standard library as a package usable on other CommonJS engines.
JavaScript
24
star
14

qq

Out of service — Extensions for the Q promise library for JavaScript
JavaScript
24
star
15

terminal

A JavaScript HTML5/VT100 Terminal Emulator
JavaScript
22
star
16

q-fs

Out of service — Use Q-IO instead.
JavaScript
21
star
17

qooqbooq

A primer on the care and feeding of asynchronous promises
JavaScript
20
star
18

tigerblood

Just kidding — Eventually Winning in JavaScript (CommonJS/Promises/A,B,D)
JavaScript
19
star
19

q-http

Out of service — Please use Q-IO
JavaScript
15
star
20

xbin

~/bin
Shell
15
star
21

wiky

A Wiki markup to and from HTML converter written in JavaScript (LGPL)
JavaScript
13
star
22

iterator

Out of service: consider "collections" — JavaScript iterator tools
JavaScript
12
star
23

mimeparse

Basic functions for handling mime-types as a JavaScript package
JavaScript
12
star
24

tusk

A JavaScript package manager
JavaScript
12
star
25

cops

A terminal UI library for Go
Go
11
star
26

whatsupdoc

Out of service — A pure JavaScript inline JavaScript documentation parser and formatter CommonJS package.
JavaScript
11
star
27

codish

A Jack/Narwhal/GAE back-end for the Codish Lexicon website.
JavaScript
10
star
28

jaque

Out of service — Use q-io/http-apps
JavaScript
10
star
29

q-require

Out of service — Please use Mr instead
JavaScript
9
star
30

fs-boot

Out of service — Please use Q-IO instead
JavaScript
8
star
31

lode

Out of service: consider "mr" — A package-aware asynchronous JavaScript module system
JavaScript
8
star
32

tale.js

Tale, a game
JavaScript
8
star
33

tale

An immersive adventure game set on the faces of a six-sided die (real-time, web, text and command mmorpg)
Python
7
star
34

thatsallfolks

A pure JavaScript template parsing and formatting package based on Narwhal's resource overlays.
JavaScript
7
star
35

gtor-demos

Animated visualizations for A General Theory of Reactivity
JavaScript
7
star
36

argunauts

JavaScript
5
star
37

url2

Augments Node.js’s URL library
JavaScript
5
star
38

pop-observe

Property, range, map, and set change observers for arrays, objects, and other instances.
JavaScript
5
star
39

mkroot

Yes, roots are my trade. I am a rooter. My name is mkroot. I arrange, design, and sell roots.
Shell
5
star
40

swl

An HTML preprocessor I wrote back in Y2K. Compare to Markdown.
Perl
4
star
41

transcode

Out of service — Character set transcoder for NodeJS, built on libiconv
C++
4
star
42

blog

Ask a Wizard blog
4
star
43

peruacru

Escape from Peruácru Island
JavaScript
3
star
44

pop-swap

Range content change operator for arrays and array like JavaScript objects
JavaScript
3
star
45

rezult

JavaScript value or error object
JavaScript
3
star
46

narwhal-node

Out of service — An old and busted implementation of a Node embedding for Narwhal.
JavaScript
3
star
47

pop-zip

Zip and unzip (also called matrix transpose) for arrays and other collections.
JavaScript
3
star
48

gol

Game of Life Demo
JavaScript
3
star
49

pop-equals

Deep equality polymorphic operator for arbitrary JavaScript objects
JavaScript
2
star
50

pop-iterate

Polymorphic iterator operator for JavaScript objects
JavaScript
2
star
51

home

My home directory
Vim Script
2
star
52

bandnames

Band name ideas (mostly bad)
2
star
53

gol.aelf.land

Game of Life Browser
JavaScript
2
star
54

jscrypto

Fast symmetric cryptography in Javascript
JavaScript
2
star
55

planes

Python on Planes: middleware and reusable applications for persistent state web services
Python
2
star
56

pop-has

Polymorphic has operator for checking whether an equivalent value exists in a JavaScript collection
JavaScript
2
star
57

watablag

Temporary.
CSS
2
star
58

silk

A smooth, free icon set, containing over 700 16-by-16 pixel icons in strokably-soft PNG format, packaged for Narwhal.
2
star
59

pop-compare

Polymorphic deep comparison operator for arbitrary JavaScript values
JavaScript
2
star
60

pop-clone

A polymorphic operator for cloning JavaScript object graphs
JavaScript
2
star
61

codi.sh

JavaScript
2
star
62

montage-simple-flow

JavaScript
2
star
63

pop-hash

A hash operator for arbitrary JavaScript objects, for browsers and Node.js
JavaScript
2
star
64

montage-repetition-demo

A demo of a bare MontageJS Repetition, with add and remove buttons in the Digit touch widget set.
JavaScript
1
star
65

montage-tree-controller-demo

A demo of the new MontageJS TreeController
JavaScript
1
star
66

pop-arrayify

Transforms arbitrary collections into arrays by whatever means they support
JavaScript
1
star
67

emone.then.land

Emonë script transcriber
JavaScript
1
star
68

kriskowal.github.io

All the things.
1
star
69

test

JavaScript
1
star
70

zp

Zero-prefixed function calls in strings
JavaScript
1
star
71

yogabylydia.com

ॐ Yoga By Lydia ॐ
HTML
1
star
72

felis-cursus

JavaScript
1
star
73

sh.codi.sh

modal web shell
JavaScript
1
star
74

mr-coffee

CoffeeScript translator for Montage Require 2
JavaScript
1
star
75

engage

JavaScript
1
star
76

delve.aelf.land

Front-end for the aelf.land world editor
JavaScript
1
star
77

pop-clear

Clears objects, arrays, and objects that override the clear method.
JavaScript
1
star
78

q-comm

Out of service — Q-Comm has been renamed Q-Connection
1
star
79

mini-map

A very small subset of ES6 Map that is good enough for small sizes
JavaScript
1
star