WSyncWebdataClient

WSyncWebdataClient

new WSyncWebdataClient(instWConverClient, optopt) → {Object}

Description:
  • 瀏覽器端之資料同步器

Source:
Example
//前後端共用範例
import w from 'wsemi'
import WSyncWebdataServer from './src/WSyncWebdataServer.mjs'
import WSyncWebdataClient from './src/WSyncWebdataClient.mjs'

let ms = []

let ntg = 0
let genTag = () => {
    ntg++
    return `tag-${ntg}`
}

//-------- 後端 ---------

//EventEmitter, 模擬後端推播至前端
let ee = w.evem()

//instWConverServer
let instWConverServer = w.evem()

//wsds
let wsds = new WSyncWebdataServer(
    instWConverServer,
    {
        // fpTableTags: 'tableTags-sync-webdata.json',
        genTag,
    },
)

//tableTagsSrv
let tableTagsSrv = {
    tabA: 'tag-0-a',
    tabB: 'tag-0-b',
}

//initTableTags
wsds.initTableTags(tableTagsSrv)

//readTableTags
console.log('server: nowTableTags', wsds.readTableTags())
ms.push({ 'server nowTableTags': JSON.stringify(wsds.readTableTags()) })

//updateTableTag
setTimeout(() => {
    wsds.updateTableTag('tabA')
    ms.push({ 'server updateTableTag': 'tabA' })
}, 500)
setTimeout(() => {
    wsds.updateTableTag('tabB')
    ms.push({ 'server updateTableTag': 'tabB' })
}, 750)
setTimeout(() => {
    wsds.updateTableTag('tabA')
    ms.push({ 'server updateTableTag': 'tabA' })
}, 1000)

//changeTableTags
wsds.on('changeTableTags', (nowTableTags) => {
    console.log('server: changeTableTags', nowTableTags)

    //server push
    console.log('server: push')
    ms.push({ 'server changeTableTags': JSON.stringify(nowTableTags) })
    ee.emit('push', nowTableTags)

})

//error
wsds.on('error', (err) => {
    console.log('server: error', err)
})

//getAPIData, 模擬後端提供API
let tabsCount = {
    tabA: 0,
    tabB: 0,
}
async function getAPIData(tableName) {
    ms.push({ 'server call getAPIData before': tableName })
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            tabsCount[tableName] += 1
            ms.push({ 'server call getAPIData after': `table[${tableName}] = ${tabsCount[tableName]}` })
            resolve(`table[${tableName}] = ${tabsCount[tableName]}`)
        }, 100)
    })
}

//-------- 前端 ---------

//instWConverClient
let instWConverClient = w.evem()

//wsdc
let wsdc = new WSyncWebdataClient(instWConverClient, {})

//tableTagsCl
let tableTagsCl = {
    tabA: 'tag-0-a',
    tabB: 'tag-0-b',
}

//setTableTags, 模擬前端將tableTags預先或有變更即儲存至localStorage, 啟動時有既有tableTags
wsdc.setTableTags(tableTagsCl)
ms.push({ 'clinet setTableTags': JSON.stringify(tableTagsCl) })

//push, 模擬前端接收後端推播有變更tableTags
ee.on('push', (nowTableTags) => {

    //updateTableTags
    wsdc.updateTableTags(nowTableTags)
    ms.push({ 'clinet updateTableTags': JSON.stringify(nowTableTags) })

})

//refreshState
wsdc.on('refreshState', (msg) => {
    console.log('client: refreshState needToRefresh', msg.needToRefresh)
})

//refreshTable
wsdc.on('refreshTable', (input) => {
    // console.log('client: refreshTable', input)

    //收到有變更tableTags, 模擬呼叫後端API
    console.log('client: getAPIData before: ' + input.tableName)
    ms.push({ 'clinet call getAPIData before': input.tableName })
    getAPIData(input.tableName)
        .then((data) => {
            console.log('client: getAPIData after: ' + data)
            ms.push({ 'clinet call getAPIData after': data })
            input.pm.resolve(data) //Use pm.resolve to retrieve the data, and pm.reject the message when get an error.
        })
        .catch((err) => {
            input.pm.reject(err)
        })

})

//getData
wsdc.on('getData', (data) => {
    console.log('client: getData', data)
    //前端取得數據
})

//beforeUpdateTableTags, afterUpdateTableTags
wsdc.on('beforeUpdateTableTags', (msg) => {
    // console.log('client: beforeUpdateTableTags', msg)
})
wsdc.on('afterUpdateTableTags', (msg) => {
    // console.log('client: afterUpdateTableTags', msg)
})

//error
wsdc.on('error', (err) => {
    console.log('client: error', err)
})

setTimeout(() => {
    console.log('ms', ms)
}, 2000)

// server: nowTableTags { tabA: 'tag-0-a', tabB: 'tag-0-b' }
// server: changeTableTags { tabA: 'tag-1', tabB: 'tag-0-b' }
// server: push
// client: refreshState needToRefresh true
// client: getAPIData before: tabA
// client: getAPIData after: table[tabA] = 1
// client: getData { tableName: 'tabA', timeTag: 'tag-1', data: 'table[tabA] = 1' }
// server: changeTableTags { tabA: 'tag-1', tabB: 'tag-2' }
// server: push
// client: refreshState needToRefresh true
// client: getAPIData before: tabB
// client: getAPIData after: table[tabB] = 1
// client: getData { tableName: 'tabB', timeTag: 'tag-2', data: 'table[tabB] = 1' }
// server: changeTableTags { tabA: 'tag-3', tabB: 'tag-2' }
// server: push
// client: refreshState needToRefresh true
// client: getAPIData before: tabA
// client: getAPIData after: table[tabA] = 2
// client: getData { tableName: 'tabA', timeTag: 'tag-3', data: 'table[tabA] = 2' }
// ms [
//   { 'server nowTableTags': '{"tabA":"tag-0-a","tabB":"tag-0-b"}' },
//   { 'clinet setTableTags': '{"tabA":"tag-0-a","tabB":"tag-0-b"}' },
//   { 'server updateTableTag': 'tabA' },
//   { 'server changeTableTags': '{"tabA":"tag-1","tabB":"tag-0-b"}' },
//   { 'clinet updateTableTags': '{"tabA":"tag-1","tabB":"tag-0-b"}' },
//   { 'clinet call getAPIData before': 'tabA' },
//   { 'server call getAPIData before': 'tabA' },
//   { 'server updateTableTag': 'tabB' },
//   { 'server call getAPIData after': 'table[tabA] = 1' },
//   { 'clinet call getAPIData after': 'table[tabA] = 1' },
//   { 'server changeTableTags': '{"tabA":"tag-1","tabB":"tag-2"}' },
//   { 'clinet updateTableTags': '{"tabA":"tag-1","tabB":"tag-2"}' },
//   { 'clinet call getAPIData before': 'tabB' },
//   { 'server call getAPIData before': 'tabB' },
//   { 'server updateTableTag': 'tabA' },
//   { 'server call getAPIData after': 'table[tabB] = 1' },
//   { 'clinet call getAPIData after': 'table[tabB] = 1' },
//   { 'server changeTableTags': '{"tabA":"tag-3","tabB":"tag-2"}' },
//   { 'clinet updateTableTags': '{"tabA":"tag-3","tabB":"tag-2"}' },
//   { 'clinet call getAPIData before': 'tabA' },
//   { 'server call getAPIData before': 'tabA' },
//   { 'server call getAPIData after': 'table[tabA] = 2' },
//   { 'clinet call getAPIData after': 'table[tabA] = 2' }
// ]
Parameters:
Name Type Attributes Default Description
instWConverClient Object

輸入通訊服務實體物件,可使用例如WConverhpClient等建立

opt Object <optional>
{}

輸入設定物件,預設{}

Properties
Name Type Attributes Default Description
autoPollingTableTagsForActive Boolean <optional>
false

輸入是否當使用者活躍時自動進行輪詢布林值,預設false

pollingDelayTime Integer <optional>
2000

輸入輪詢強制延遲時間整數,單位ms,預設2000

refreshTimeout Integer <optional>
0

輸入等待refreshTable與refreshTags事件回覆之上限時間整數,單位ms,預設0代表不限。逾時僅結束該次等待並發出error事件,逾時後才回覆之資料仍會依序提交

Returns:

回傳前端資料同步物件,可監聽事件refreshTags、beforeUpdateTableTags、refreshState、refreshTable、getData、afterUpdateTableTags、error,可使用函數setTableTags、updateTableTags、pollingTableTags、clearSync。refreshTags與refreshTable事件之輸入物件帶有pm(回覆通道),監聽器須為同步函數,並於每條路徑以pm.resolve回傳資料或以pm.reject回傳錯誤(非同步工作須自行catch後以pm回覆);無監聽器、或監聽器於回覆前同步拋錯時,該pm由本套件以reject終結並視為該次失敗。某表取資料失敗時不推進其時間戳並發出error事件(內容為{msg,err,tableName,timeTag}),之後再收到同一時間戳時會重拉。同一表有多個請求時只提交序號較新之回應(時間戳不倒退),只有最新之請求會報錯;同一時刻多則推播所產生之同表請求只派發最新者,已派發而被取代之請求其批次即結束等待,故該批次之afterUpdateTableTags可能早於該表資料送達。監聽器同步拋錯時轉為error事件通知,本套件自發之error若無監聽者則改以console.error輸出,不會使行程崩潰;getData監聽器拋錯時該表時間戳已推進,不會因此重拉。表名不得為__proto__。同一事件物件只能建立一個本同步器,重建前須先呼叫clearSync

Type
Object

Methods

(static) clearSync()

Description:
  • 釋放資源:移除自動輪詢之監聽,取消已排程之事件,結束進行中之等待(其後回覆之結果不再提交),之後各函數皆不作用且不再派發任何事件,可重複呼叫。釋放前已提交之時間戳,其getData若尚未派發則不再派發

Source:
Example
wsdc.clearSync()

(async, static) pollingTableTags()

Description:
  • 主動觸發輪詢更新各資料表之時間戳,回傳之promise恆resolve。輪詢中重複呼叫時直接返回;等待期間若已有其他時間戳被套用,本次回覆可能較舊而捨棄

Source:
Example
wsdc.pollingTableTags()

(static) setTableTags(tableTags)

Description:
  • 直接設定各資料表時間資料,供啟動時還原既有時間戳使用,傳入之物件將直接作為內部狀態(之後之更新會就地修改該物件)

Source:
Example
let tableTags = {...}
wsdc.setTableTags(tableTags)
Parameters:
Name Type Description
tableTags Object

輸入各資料表時間戳物件,null視同{},其他非物件則發出error事件且不作用

(async, static) updateTableTags(tableTags)

Description:
  • 主動更新指定資料表之時間戳,當有新的資料表時間戳資料時調用此函數進行更新,回傳之promise恆resolve,各表之成敗以getData或error事件通知

Source:
Example
let tableTags = {...}
wsdc.updateTableTags(tableTags)
Parameters:
Name Type Description
tableTags Object

輸入各資料表時間戳物件,非物件(null除外)時發出error事件且不作用