我是新手,我正在尝试使用websocket获取温度,以下是用于使用websockets获取温度的代码。
ws.js
const webSock = () => {
let socket = new WebSocket("ws://localhost:54321/webTest");
let temperature = 0;
const getTemperature = () => {
return temperature;
}
socket.onopen = function (e) {
console.log("[open] Connection established");
console.log("Sending to server");
};
socket.onmessage = function (event) {
var message = JSON.parse(event.data);
temperature = data.message;
console.log(temperature);
};
socket.onclose = function (event) {
console.log(event.reason);
};
socket.onerror = function (error) {
console.log(`[error] ${error.message}`);
};
const sendMessage = () => {
var msg = {
'data': 'hello'
};
console.log(msg);
socket.send(JSON.stringify(msg));
}
return {getTemperature};
};
export default webSock;
下面是 App.svelte
上的代码<script>
import WS from "./ws.js";
const ws = WS();
$: temperature = ws.getTemperature();
</script>
<main>
<h1>{temperature}</h1>
</main>
网页显示为零,这是初始值,并且没有进一步变化,但是在Web浏览器的控制台中,由于控制台日志语句,我能够获取温度
请指出正确的方向来解决此问题。
谢谢
答案 0 :(得分:5)
漂亮的小ws模块:)
所以,问题是您的ws.getTemperature()
方法没有反应性。因此,尽管您在反应式表达式$:
中使用Svelte不会知道该值何时更改,因此它将仅运行一次。
您不仅需要传播值,还需要传播变更。。
在老式JS中,我们将通过回调来实现。您可以像这样修改代码,例如:
let _callback
const getTemperature = callback => {
_callback = callback // <- save a callback for future change
callback(temperature)
}
socket.onmessage = function (event) {
var data = JSON.parse(event.data);
temperature = data.message;
console.log(temperature);
if (_callback) _callback(temperature)
};
然后在您的Svelte组件中,您可以订阅以下数据源:
<script>
import WS from "./ws.js";
const ws = WS();
let temperature
ws.getTemperature(value => {
temperature = value // <- Svelte will see that, it's reactive!
})
</script>
<main>
<h1>{temperature}</h1>
</main>
在这里,更改将被传播,因为我们正在分配给组件的顶级变量。 Svelte使用分配(=
来通知值已更改。
此代码将适用于您要执行的操作。现在,在Svelte中,您可以使用商店。商店本质上是某种简化的流(或在ES中称为“可观察”的流),即它们表示随时间变化的值。与我们的回调示例相同,不同之处在于它们提供了一些其他非常有用的工具(例如计算从其他存储中派生的值),并且在Svelte组件中提供了一种巧妙的语法。当您需要从常规JS来源导入“反应性”时,商店就是惯用的Svelte方式。有关完整参考,请参见docs。
这是我们改用商店重写回调示例的方法:
// writable are the simplest form of stores
import { writable } from 'svelte/store'
const webSock = () => {
let socket = new WebSocket("ws://localhost:54321/webTest");
// our temperature is now a store with initial value 0
const temperature = writable(0);
// now we don't need to change this function, the change will be propaged
// by the store itself
const getTemperature = () => {
return temperature;
}
socket.onmessage = function (event) {
var data = JSON.parse(event.data);
// temperature = data.message;
// we update the value of our (writable) store,
// this will propagate the change
temperature.set(data.message)
};
// ... rest of the code
return { getTemperature };
};
export default webSock;
然后在Svelte组件中,可以使用具有特殊$
前缀语法的商店来访问商店的 value (因为temperature
变量是对商店本身的引用,这只是达到目的的一种手段,我们需要的结果是 value ):
<script>
import WS from "./ws.js";
const ws = WS();
const temperature = we.getTemperature()
console.log(temperature) // log the store, for the fun
// but what we want is the value, that we access with the special $ syntax
$: temp = $temperature
// for debug: this will log the value every time it changes
$: console.log(temp)
</script>
<main>
<!-- you can use the $ prefixed value directly in the template -->
<!-- (so we actually don't need the reactive expression above, in this example) -->
<h1>{$temperature}</h1>
</main>
所以,很好,我们的代码更精简了……但这还不是全部! Svelte商店还具有非常方便的功能来处理资源处置。即,您打开一个WS:您将需要关闭它。斯维尔特(Svelte)商店可以提供帮助。
实际上,我们上面看到的$
语法实际上将为商店设置订阅。当组件被销毁时,订阅将被取消。如果商店由多个组件订阅,则仅在最后一个组件取消订阅时才会处置该商店(如果进行了新的订阅,它将被重新初始化)。在您的代码中管理一次性物品的生命周期非常方便。
要使用此功能,我们需要使用一些更高级的readable
存储。这是为此更新的示例:
import { readable } from 'svelte/store'
// a readable store with initial value 0
//
// we pass it a function; the first argument of the function will let us update
// the value when it changes
//
export const temperature = readable(0, set => {
// this function is called once, when the first subscriber to the store arrives
let socket = new WebSocket("ws://localhost:54321/webTest");
socket.onmessage = function (event) {
var data = JSON.parse(event.data);
// we're using the `set` function we've been provided to update the value
// of the store
set(data.message)
};
// ... the rest of your socket code
const dispose = () => {
socket.close()
}
// the function we return here will be called when the last subscriber
// unsubscribes from the store (hence there's 0 subscribers left)
return dispose
})
使用者组件与上一个示例几乎没有变化。唯一的区别是我们将获得对商店的引用的方式(因为现在商店是从JS模块导出的):
<script>
import { temperature } from './ws.js'
// log the value
$: console.log($temperature)
// draw the rest of the owl
</script>
...
在这里!现在,您可以将整个WS逻辑封装在JS模块中。这样可以很好地分离关注点。 Svelte也可以自动管理您的WS生命周期! (而且我们已经涵盖了75%的商店主题。。。它们很高效,而且很简单!)
注意我还没有深入检查过从您的示例粘贴的代码,这似乎有一些小错误,但是我敢肯定,您会了解总体思路,您可以自己修复这些问题。