如何在WebSocket的onmessage事件外部使用实时加密货币价格并计算组合资产总价
如何在WebSocket的onmessage外部访问实时加密货币价格并计算总价?
我利用空闲时间学习JavaScript,近期遇到一个技术问题。我通过WebSocket获取加密货币的实时价格,代码如下:
let ethws = new WebSocket('wss://stream.binance.com:9443/ws/ethusdt@trade'); let btcws = new WebSocket('wss://stream.binance.com:9443/ws/btcusdt@trade'); let ethstockPriceElement = document.getElementById('eth-stock-price') let btcstockPriceElement = document.getElementById('btc-stock-price') let ethlastPrice = null; let btclastPrice = null; ethws.onmessage = (event) => { let ethstockObject = JSON.parse(event.data) let ethprice = parseFloat(ethstockObject.p).toFixed(2) ethstockPriceElement.innerText = ethprice ethstockPriceElement.style.color = !ethlastPrice || ethlastPrice === ethprice ? 'black' : ethprice > ethlastPrice ? 'green' : 'red'; ethlastPrice = ethprice } btcws.onmessage = (event) => { let btcstockObject = JSON.parse(event.data) let btcprice = parseFloat(btcstockObject.p).toFixed(2) btcstockPriceElement.innerText = btcprice btcstockPriceElement.style.color = !btclastPrice || btclastPrice === btcprice ? 'black' : btcprice > btclastPrice ? 'green' : 'red'; btclastPrice = btcprice }
我希望将获取到的实时价格存入onmessage事件外部的可变变量中,以便计算2个BTC加3个ETH的实时总价(即2*btcprice + 3*ethprice),但目前无法在onmessage事件外部使用这些价格数据,请问实现该需求的最佳方法是什么?
解决方案
嘿,这个问题其实很常见,核心是要确保外部变量能被onmessage正确更新,并且在价格变化时自动触发总价计算。我给你几个从简单到健壮的方案:
方案1:直接复用已定义的全局变量(最快捷)
你其实已经在代码里定义了ethlastPrice和btclastPrice这两个外部变量!只是可能没意识到可以直接在需要的地方调用它们。不过要注意初始值是null,计算前得先判断两个价格都已获取到。
可以新增一个计算总价的函数,每次价格更新时调用它:
// 假设页面上有显示总价的元素 let totalPriceElement = document.getElementById('total-price'); // 计算总价的函数 function calculateTotal() { // 确保两个价格都已初始化,避免NaN if (!ethlastPrice || !btclastPrice) return; // 注意:toFixed会把数字转成字符串,要先转回数字再计算 const total = (2 * parseFloat(btclastPrice)) + (3 * parseFloat(ethlastPrice)); totalPriceElement.innerText = total.toFixed(2); } // 修改WebSocket回调,每次更新价格后触发计算 ethws.onmessage = (event) => { let ethstockObject = JSON.parse(event.data) let ethprice = parseFloat(ethstockObject.p).toFixed(2) ethstockPriceElement.innerText = ethprice ethstockPriceElement.style.color = !ethlastPrice || ethlastPrice === ethprice ? 'black' : ethprice > ethlastPrice ? 'green' : 'red'; ethlastPrice = ethprice // 调用总价计算 calculateTotal(); } btcws.onmessage = (event) => { let btcstockObject = JSON.parse(event.data) let btcprice = parseFloat(btcstockObject.p).toFixed(2) btcstockPriceElement.innerText = btcprice btcstockPriceElement.style.color = !btclastPrice || btclastPrice === btcprice ? 'black' : btcprice > btclastPrice ? 'green' : 'red'; btclastPrice = btcprice // 调用总价计算 calculateTotal(); }
这样每次BTC或ETH价格更新时,都会自动计算并更新总价。
方案2:用对象统一管理价格状态(更整洁)
如果后续要新增更多币种,用一个对象集中管理所有价格会更清晰,避免零散的全局变量:
// 统一管理所有加密货币价格 const cryptoPrices = { eth: null, btc: null }; let totalPriceElement = document.getElementById('total-price'); function calculateTotal() { const { eth, btc } = cryptoPrices; if (!eth || !btc) return; // 这里直接用数字计算,避免字符串运算的坑 const total = (2 * btc) + (3 * eth); totalPriceElement.innerText = total.toFixed(2); } ethws.onmessage = (event) => { let ethstockObject = JSON.parse(event.data) // 先保留数字类型,显示时再转成两位小数 const ethprice = parseFloat(ethstockObject.p); ethstockPriceElement.innerText = ethprice.toFixed(2) ethstockPriceElement.style.color = !cryptoPrices.eth || cryptoPrices.eth === ethprice ? 'black' : ethprice > cryptoPrices.eth ? 'green' : 'red'; cryptoPrices.eth = ethprice calculateTotal(); } btcws.onmessage = (event) => { let btcstockObject = JSON.parse(event.data) const btcprice = parseFloat(btcstockObject.p); btcstockPriceElement.innerText = btcprice.toFixed(2) btcstockPriceElement.style.color = !cryptoPrices.btc || cryptoPrices.btc === btcprice ? 'black' : btcprice > cryptoPrices.btc ? 'green' : 'red'; cryptoPrices.btc = btcprice calculateTotal(); }
这个方案的优势:
- 所有价格状态集中管理,逻辑更清晰
- 保留数字类型计算,避免字符串拼接的错误(比如不小心用
+号导致字符串相加)
方案3:使用自定义事件(更解耦)
如果总价计算逻辑和WebSocket回调属于不同模块,用自定义事件可以实现代码解耦:
// 定义价格更新的自定义事件触发函数 function dispatchPriceUpdate(symbol, price) { const event = new CustomEvent('priceUpdated', { detail: { symbol, price } }); window.dispatchEvent(event); } // WebSocket回调中触发事件 ethws.onmessage = (event) => { let ethstockObject = JSON.parse(event.data) const ethprice = parseFloat(ethstockObject.p); ethstockPriceElement.innerText = ethprice.toFixed(2) ethstockPriceElement.style.color = !ethlastPrice || ethlastPrice === ethprice ? 'black' : ethprice > ethlastPrice ? 'green' : 'red'; ethlastPrice = ethprice dispatchPriceUpdate('eth', ethprice); } btcws.onmessage = (event) => { let btcstockObject = JSON.parse(event.data) const btcprice = parseFloat(btcstockObject.p); btcstockPriceElement.innerText = btcprice.toFixed(2) btcstockPriceElement.style.color = !btclastPrice || btclastPrice === btcprice ? 'black' : btcprice > btclastPrice ? 'green' : 'red'; btclastPrice = btcprice dispatchPriceUpdate('btc', btcprice); } // 在需要计算总价的地方监听事件 const priceStore = { eth: null, btc: null }; window.addEventListener('priceUpdated', (e) => { const { symbol, price } = e.detail; priceStore[symbol] = price; const { eth, btc } = priceStore; if (eth && btc) { const total = (2 * btc) + (3 * eth); document.getElementById('total-price').innerText = total.toFixed(2); } });
这个方案适合大型项目,把价格更新和业务逻辑(计算总价)分离,代码更易维护。
额外小提示
- 尽量保留价格的数字类型用于计算,
toFixed只用来格式化显示,避免字符串运算的问题 - 必须判断价格是否初始化,防止
null参与计算导致NaN - 如果价格更新太频繁,可以加防抖优化,避免重复计算:
let debounceTimer; function calculateTotal() { clearTimeout(debounceTimer); debounceTimer = setTimeout(() => { const { eth, btc } = cryptoPrices; if (!eth || !btc) return; const total = (2 * btc) + (3 * eth); totalPriceElement.innerText = total.toFixed(2); }, 100); // 100ms内多次更新只计算一次 }
内容的提问来源于stack exchange,提问作者Stan Daily
相关产品推荐
相关产品推荐

