2017-04-25 189 views
0

在我當前的項目中,我正在處理firebase websocket訂閱。不同的組件可以訂閱不同的數據,例如,在每個ListItem組件的訂單列表中,通過分派componentDidMount中的SUBSCRIBE動作和通過分派componentWillUnmount中的UNSUBSCRIBE動作取消訂閱,訂閱了該特定項目的websocket「事件」。使用redux-saga處理訂閱/取消訂閱大量事件

我的傳奇故事是這樣的:

const subscriptions = {} 

export function * subscribeLoop() { 
    while (true) { 
    const { path } = yield take(SUBSCRIBE) 
    subscriptions[path] = yield fork(subscription, path) 
    } 
} 

export function * unsubscribeLoop() { 
    while (true) { 
    const { path } = yield take(UNSUBSCRIBE) 
    yield cancel(subscriptions[path]) 
    } 
} 

export function * subscription (path) { 
    let ref 

    try { 
    const updateChannel = channel() 

    ref = api.child(path) 
    ref.on('value', snapshot => { 
     updateChannel.put(snapshot.val()) 
    }) 

    while (true) { 
     const data = yield take(updateChannel) 
     yield put(handleUpdate(path, data)) 
    } 
    } finally { 
    if (yield cancelled()) { 
     ref.off() 
     ref = null 
    } 
    } 
} 

我想這是不處理這個正確的方式 - 它確實是500個項目的清單上相當緩慢。

如何優化性能?

  • 我是否還需要分叉?
  • 我應該引入某種延遲來給線程一些空間來處理其他事情嗎?

任何提示表示讚賞。

回答

0

我應該引入某種延遲來給線程一些空間來處理其他事情嗎?

首先需要記住的是,使用redux saga和fork等效果實際上不會創建任何會在無限循環中扭曲的線程。它僅僅是用於組織回調鏈的語法糖,因爲yield運算符提供了雙方中的對象傳遞。從這個角度來看,強制延遲的問題並不合理 - 因爲線程並不存在。

我甚至需要叉嗎?

在適當的技巧的情況下,通常可以沒有設置的通話分叉,並在一個根傳奇中做所有事情。這個想法是使用websocket上當前詞彙區域中的回調函數進行訂閱,並期望在延遲承諾的基礎上獲得僞無限循環中的消息。

概念上的代碼可以看看大約如此:

const subscribers = new Map() 

function * webSocketLoop() { 
    let resolver = null 
    let promise = new Promise(resolve => (resolver = resolve)) 
    let message = null; 

    websocket.on('message', (payload) => { 
    message = Object.assign({}, payload) 
    resolver() 
    promise = promise.then(() => new Promise(resolve => (resolver = resolve))) 
    }) 

    while(true) { 
    yield call(() => promise) 
    const type = message.type 
    const handlers = subscribers.get(type) || [] 
    handlers.forEach(func => func(message)) 
    } 
} 

export function * mainSaga() { 
    yield takeEvery(SUBSCRIBE, subscribe) 
    yield takeEvery(UNSUBSCRIBE, unsubscribe) 
    yield fork(webSocketLoop) 
}