 @objc(JSBridge)
 public class JSBridge : RCTEventEmitter {
 
+    public typealias Callback = ([String: NSObject]) -> Void
+    
     var registeredActions: Set<String> = []
     var actionCounter: NSInteger = 0
+    // cache for responses from js
     var replyCache = [NSInteger: [String: NSObject]]()
+    // semaphores waiting for replies from js
     var eventSemaphores = [NSInteger: dispatch_semaphore_t]()
-    private let semaphoresDispatchQueue = dispatch_queue_create("com.cliqz.jsbridge.sync", DISPATCH_QUEUE_CONCURRENT)
+    // callbacks waiting for replies from js
+    var eventCallbacks = [NSInteger: Callback]()
+    // Dictionary of actions waiting for a function to be registered before executing
+    var awaitingRegistration = [String: Array<(Array<AnyObject>, Callback)>]()
+    
+    // serial queue for access to eventSemaphores and eventCallbacks
+    private let semaphoresDispatchQueue = dispatch_queue_create("com.cliqz.jsbridge.sync", DISPATCH_QUEUE_SERIAL)
+    // serial queue for access to actionCounter
+    private let lockDispatchQueue = dispatch_queue_create("com.cliqz.jsbridge.lock", DISPATCH_QUEUE_SERIAL)
+    // dispatch queue for executing action callbacks
+    private let callbackDispatchQueue = dispatch_queue_create("com.cliqz.jsbridge.callback", DISPATCH_QUEUE_CONCURRENT)
+    
     let ACTION_TIMEOUT : Int64 = 200000000 // 200ms
     
     public override init() {

        return ["callAction", "publishEvent"]
    }
    
    public func callAction(functionName: String, args: AnyObject) -> [String: NSObject] {
        // check listener is registered on other end
        guard self.registeredActions.contains(functionName) else {
            return ["error": "function not registered"]
        }
        
        // create unique id
        actionCounter += 1
        let actionId = actionCounter
        
        // create a semaphore for this action
        let sem = dispatch_semaphore_create(0)

            self.eventSemaphores[actionId] = sem
        }
        
        // dispatch event
        self.sendEventWithName("callAction", body: ["id": actionId, "action": functionName, "args": args])
        
