-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcommune.coffee
120 lines (94 loc) · 3.18 KB
/
commune.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
###
* Commune.js
* Web workers lose their chains
* 0.2.2
* Easy, DRY, transparent worker threads for your app
* Dan Motzenbecker
* http://oxism.com
* MIT License
###
communes = {}
makeBlob = null
mime = 'application\/javascript'
class Commune
constructor: (fnString) ->
if fnString.match /\bthis\b/
console?.warn '''
Commune: Referencing `this` within a worker process might not work as expected.
`this` will refer to the worker itself or an object created within the worker.
'''
if (lastReturnIndex = fnString.lastIndexOf 'return') is -1
throw new Error 'Commune: Target function has no return statement.'
@blobUrl = makeBlob (fnString[...lastReturnIndex] +
"""
self.postMessage(#{ fnString.substr(lastReturnIndex).replace /return\s+|;|\}$/g, '' });
}
""").replace(/^function(.+)?\(/, 'function __communeInit(') +
'''
if (typeof window === 'undefined') {
self.addEventListener('message', function(e) {
__communeInit.apply(this, e.data);
});
}
'''
spawnWorker: (args, cb) ->
worker = new Worker @blobUrl
worker.addEventListener 'message', (e) ->
cb e.data
worker.terminate()
worker.postMessage args
threadSupport = do ->
try
testBlob = new @Blob
Blob = @Blob
catch e
Blob = @BlobBuilder or @WebKitBlobBuilder or @MozBlobBuilder or false
URL = @URL or @webkitURL or @mozURL or false
return false unless Blob and URL and @Worker
testString = 'true'
try
if Blob is @Blob
testBlob = new Blob [testString], type: mime
makeBlob = (string) -> URL.createObjectURL new Blob [string], type: mime
else
testBlob = new Blob
testBlob.append testString
testBlob = testBlob.getBlob mime
makeBlob = (string) ->
blob = new Blob
blob.append string
URL.createObjectURL blob.getBlob mime
testUrl = URL.createObjectURL testBlob
testWorker = new Worker testUrl
testWorker.terminate()
true
catch e
if e.name is 'SECURITY_ERR'
console?.warn 'Commune: Cannot provision workers when serving ' +
'via `file://` protocol. Serve over http(s) to use worker threads.'
false
@commune = (fn, args, cb) ->
unless typeof fn is 'function'
throw new Error 'Commune: Must pass a function as first argument.'
if typeof args is 'function'
cb = args
args = []
if threadSupport
fnString = fn.toString()
unless communes[fnString]
unless typeof cb is 'function'
throw new Error 'Commune: Must pass a callback to use worker result.'
commune = communes[fnString] = new Commune fnString
else
commune = communes[fnString]
commune.spawnWorker args, cb
else
setTimeout (-> cb fn.apply @, args), 0
@communify = (fn, args) ->
if args
(cb) -> commune fn, args, cb
else
(args, cb) -> commune fn, args, cb
@commune.isThreaded = -> threadSupport
@commune.disableThreads = -> threadSupport = false
@commune.enableThreads = -> threadSupport = true