Replace Task's implementation with ProcessTask.

This commit is contained in:
Cheng Zhao
2013-03-24 19:20:31 +08:00
parent 3c5a79710a
commit b5be1c378a
6 changed files with 24 additions and 148 deletions

View File

@@ -1,37 +0,0 @@
global.window = {}
global.attachEvent = ->
console =
warn: -> callTaskMethod 'warn', arguments...
log: -> callTaskMethod 'log', arguments...
error: -> callTaskMethod 'error', arguments...
global.__defineGetter__ 'console', -> console
window.document =
createElement: ->
setAttribute: ->
getElementsByTagName: -> []
appendChild: ->
documentElement:
insertBefore: ->
removeChild: ->
getElementById: -> {}
createComment: -> {}
createDocumentFragment: -> {}
global.document = window.document
# `callTaskMethod` can be used to invoke method's on the parent `Task` object
# back in the window thread.
global.callTaskMethod = (method, args...) ->
process.send(method: method, args: args)
# The worker's initial handler replaces itglobal when `start` is invoked
global.handler =
start: ({globals, handlerPath}) ->
for key, value of globals
global[key] = value
window[key] = value
global.handler = require(handlerPath)
callTaskMethod 'started'
process.on 'message', (data) ->
handler[data.method]?(data.args...) if data.method

View File

@@ -1,61 +0,0 @@
_ = require 'underscore'
child_process = require 'child_process'
EventEmitter = require 'event-emitter'
fs = require 'fs-utils'
module.exports =
class ProcessTask
aborted: false
constructor: (@path) ->
start: ->
throw new Error("Task already started") if @worker?
# Equivalent with node --eval "...".
blob = "require('coffee-script'); require('process-task-shell');"
@worker = child_process.fork '--eval', [ blob ], cwd: __dirname
@worker.on 'message', (data) =>
if @aborted
@done()
return
if data.method and this[data.method]
this[data.method](data.args...)
else
@onMessage(data)
@startWorker()
log: -> console.log(arguments...)
warn: -> console.warn(arguments...)
error: -> console.error(arguments...)
startWorker: ->
@callWorkerMethod 'start',
globals:
navigator:
userAgent: navigator.userAgent
handlerPath: @path
started: ->
onMessage: (message) ->
callWorkerMethod: (method, args...) ->
@postMessage({method, args})
postMessage: (data) ->
@worker.send(data)
abort: ->
@aborted = true
done: ->
@abort()
@worker?.kill()
@worker = null
@trigger 'task-completed'
_.extend ProcessTask.prototype, EventEmitter

View File

@@ -1,17 +1,10 @@
# This file is loaded within Task's worker thread. It will attempt to invoke
# any message with a 'method' and 'args' key on the global `handler` object. The
# initial `handler` object contains the `start` method, which is called by the
# task itself to relay information from the window thread and bootstrap the
# worker's environment. The `start` method then replaces the handler with an
# object required from the given `handlerPath`.
self.window = {}
self.attachEvent = ->
global.window = {}
global.attachEvent = ->
console =
warn: -> callTaskMethod 'warn', arguments...
log: -> callTaskMethod 'log', arguments...
error: -> callTaskMethod 'error', arguments...
self.__defineGetter__ 'console', -> console
global.__defineGetter__ 'console', -> console
window.document =
createElement: ->
@@ -24,21 +17,21 @@ window.document =
getElementById: -> {}
createComment: -> {}
createDocumentFragment: -> {}
self.document = window.document
global.document = window.document
# `callTaskMethod` can be used to invoke method's on the parent `Task` object
# back in the window thread.
self.callTaskMethod = (method, args...) ->
postMessage(method: method, args: args)
global.callTaskMethod = (method, args...) ->
process.send(method: method, args: args)
# The worker's initial handler replaces itself when `start` is invoked
self.handler =
# The worker's initial handler replaces itglobal when `start` is invoked
global.handler =
start: ({globals, handlerPath}) ->
for key, value of globals
self[key] = value
global[key] = value
window[key] = value
self.handler = require(handlerPath)
global.handler = require(handlerPath)
callTaskMethod 'started'
self.addEventListener 'message', ({data}) ->
process.on 'message', (data) ->
handler[data.method]?(data.args...) if data.method

View File

@@ -1,9 +1,10 @@
_ = require 'underscore'
child_process = require 'child_process'
EventEmitter = require 'event-emitter'
fs = require 'fs-utils'
module.exports =
class Task
class ProcessTask
aborted: false
constructor: (@path) ->
@@ -11,9 +12,11 @@ class Task
start: ->
throw new Error("Task already started") if @worker?
blob = new Blob(["require('coffee-script'); require('task-shell');"], type: 'text/javascript')
@worker = new Worker(URL.createObjectURL(blob))
@worker.onmessage = ({data}) =>
# Equivalent with node --eval "...".
blob = "require('coffee-script'); require('task-shell');"
@worker = child_process.fork '--eval', [ blob ], cwd: __dirname
@worker.on 'message', (data) =>
if @aborted
@done()
return
@@ -22,6 +25,7 @@ class Task
this[data.method](data.args...)
else
@onMessage(data)
@startWorker()
log: -> console.log(arguments...)
@@ -43,15 +47,15 @@ class Task
@postMessage({method, args})
postMessage: (data) ->
@worker.postMessage(data)
@worker.send(data)
abort: ->
@aborted = true
done: ->
@abort()
@worker?.terminate()
@worker?.kill()
@worker = null
@trigger 'task-completed'
_.extend Task.prototype, EventEmitter
_.extend ProcessTask.prototype, EventEmitter