用戶量量大,數據量大,並且要求實時更新數據的時候,須要使用websocket。
tradingview正好就是這樣的應用場景。html
圖表調用的getBars方法:git
TVjsApi.prototype.getBars = function(symbolInfo, resolution, rangeStartDate, rangeEndDate, onLoadedCallback) { //console.log(' >> :', this.formatt(rangeStartDate*1000), this.formatt(rangeEndDate*1000)) var ticker = this.symbol + "-" + resolution; var tickerload = ticker + "load"; var tickerstate = ticker + "state"; if(!this.cacheData[ticker] && !this.cacheData[tickerstate]){ //若是緩存沒有數據,並且未發出請求,記錄當前節點開始時間 this.cacheData[tickerload] = rangeStartDate; //發起請求,從websocket獲取當前時間段的數據 this.initMessage(symbolInfo, resolution, rangeStartDate, rangeEndDate, onLoadedCallback); //設置狀態爲true this.cacheData[tickerstate] = !0; return false; } if(!this.cacheData[tickerload] || this.cacheData[tickerload] > rangeStartDate){ //若是緩存有數據,可是沒有當前時間段的數據,更新當前節點時間 this.cacheData[tickerload] = rangeStartDate; //發起請求,從websocket獲取當前時間段的數據 this.initMessage(symbolInfo, resolution, rangeStartDate, rangeEndDate, onLoadedCallback); //設置狀態爲true this.cacheData[tickerstate] = !0; return false; } if(this.cacheData[tickerstate]){ //正在從websocket獲取數據,禁止一切操做 return false; } //ticker = this.symbol + "-" + this.interval; //若是緩存有數據,且長度不爲0,構造數據 if (this.cacheData[ticker] && this.cacheData[ticker].length) { this.isLoading = false var newBars = [] this.cacheData[ticker].forEach(item => { if (item.time >= rangeStartDate * 1000 && item.time <= rangeEndDate * 1000) { newBars.push(item) } }) onLoadedCallback(newBars) } else { //若是沒有數據,等待10ms,再執行一次 var self = this this.getBarTimer = setTimeout(function() { self.getBars(symbolInfo, resolution, rangeStartDate, rangeEndDate, onLoadedCallback) }, 10) } }
獲取歷史數據list的init方法:github
TVjsApi.prototype.initMessage = function(symbolInfo, resolution, rangeStartDate, rangeEndDate, onLoadedCallback){ //console.log('發起請求,從websocket獲取當前時間段的數據'); var that = this; //保留當前回調 that.cacheData['onLoadedCallback'] = onLoadedCallback; //獲取須要請求的數據數目 var limit = that.initLimit(resolution, rangeStartDate, rangeEndDate); //商品名 var symbol = that.symbol; //若是當前時間顆粒已經改變,中止上一個時間顆粒的訂閱,修改時間節點值 if(that.interval !== resolution){ that.unSubscribe(that.interval) that.interval = resolution; } //獲取當前時間段的數據,在onMessage中執行回調onLoadedCallback if (that.interval < 60) { that.socket.send({ cmd: 'req', args: ["candle.M"+resolution+"."+symbol, limit, rangeEndDate], id: 'trade.M'+ resolution +'.'+ symbol.toLowerCase() }) } else if (that.interval >= 60) { that.socket.send({ cmd: 'req', args: ["candle.H"+(resolution/60)+"."+symbol, limit, rangeEndDate], id: 'trade.H'+ (resolution / 60) +'.'+ symbol.toLowerCase() }) } else { that.socket.send({ cmd: 'req', args: ["candle.D1."+symbol, limit, rangeEndDate], id: 'trade.D1.'+ symbol.toLowerCase() }) } }
響應websocket的Message方法:web
TVjsApi.prototype.onMessage = function(data) { var thats = this; // console.log("這是後臺返回的數據"+count+":"+JSON.stringify(data) ) if (data.data && data.data.length) { //websocket返回的值,數組表明時間段歷史數據,不是增量 var list = [] var ticker = thats.symbol + "-" + thats.interval; var tickerstate = ticker + "state"; //var that = thats; //遍歷數組,構造緩存數據 data.data.forEach(function(element) { list.push({ time: element.id*1000, open: element.open, high: element.high, low: element.low, close: element.close, volume: element.quote_vol }) }, thats) //若是沒有緩存數據,則直接填充,發起訂閱 if(!thats.cacheData[ticker]){ /*thats.cacheData[ticker] = thats.cacheData[ticker].concat(list); thats.cacheData['onLoadedCallback'](list); }else{*/ thats.cacheData[ticker] = list; thats.subscribe() } //新數據即當前時間段須要的數據,直接餵給圖表插件 if(thats.cacheData['onLoadedCallback']){ thats.cacheData['onLoadedCallback'](list); } //請求完成,設置狀態爲false thats.cacheData[tickerstate] = !1; //記錄當前緩存時間,即數組最後一位的時間 thats.lastTime = thats.cacheData[ticker][thats.cacheData[ticker].length - 1].time } if (data.type && data.type.indexOf(thats.symbol.toLowerCase()) !== -1) { // console.log(' >> sub:', data.type) // data帶有type,即返回的是訂閱數據, //緩存的key var ticker = thats.symbol + "-" + thats.interval; //構造增量更新數據 var barsData = { time: data.id * 1000, open: data.open, high: data.high, low: data.low, close: data.close, volume: data.quote_vol } /*if (barsData.time >= thats.lastTime && thats.cacheData[ticker] && thats.cacheData[ticker].length) { thats.cacheData[ticker][thats.cacheData[ticker].length - 1] = barsData }*/ //若是增量更新數據的時間大於緩存時間,並且緩存有數據,數據長度大於0 if (barsData.time > thats.lastTime && thats.cacheData[ticker] && thats.cacheData[ticker].length) { //增量更新的數據直接加入緩存數組 thats.cacheData[ticker].push(barsData) //修改緩存時間 thats.lastTime = barsData.time }else if(barsData.time == thats.lastTime && thats.cacheData[ticker].length){ //若是增量更新的時間等於緩存時間,即在當前時間顆粒內產生了新數據,更新當前數據 thats.cacheData[ticker][thats.cacheData[ticker].length - 1] = barsData } // 通知圖表插件,能夠開始增量更新的渲染了 thats.datafeeds.barsUpdater.updateData() } }
代碼邏輯以下:數組
以上邏輯基本含括了用戶的兩個重要操做:切換時間顆粒、查看歷史記錄。
可運行代碼在GitHub上已經更新,可預覽。緩存