Creating multiple WebSocket connections in nodejs in parallel - javascript

Hi as in the title I wanna create multiple WebSocket clients in node, so I decided to create a class that would be managing a single connection and then creates an X instance of this class.
Here is my code
class CreateNewConnection {
constructor () {
this.ws = new WebSocket('wss://echo.websocket.org/', {
origin: 'https://websocket.org'
})
this.ws.on('open', function open () {
console.log('connected')
this.ws.send(Date.now())
})
this.ws.on('close', function close () {
console.log('disconnected')
})
this.ws.on('message', function incoming (data) {
console.log(`Roundtrip time: ${Date.now() - data} ms`)
setTimeout(function timeout () {
this.ws.send(Date.now())
}, 500)
})
}
}
I am getting an error
this.ws.send(Date.now())
TypeError: Cannot read property 'send' of undefined
Anybody have any ideas why this isn't working? P.S I am using ws library

You are trying to call send method from closure. To abolish closure you have 2 ways:
You need to use arrow functions between class's constructor closure and your send method call:
this.ws.on('message', (data) => {
console.log(\`Roundtrip time: ${Date.now() - data} ms\`)
setTimeout(() => {
this.ws.send(Date.now())
}, 500)
})
You need to create variable which would refers to class this context:
constructor () {
var _this = this;
// code code code
_this.ws.send(Date.now());
Here you can read about arrow functions:
https://javascript.info/arrow-functions-basics
And here about closures:
https://medium.com/#prashantramnyc/javascript-closures-simplified-d0d23fa06ba4
TL;DR
Your this.ws.send(Date.now()) refers to timeout function this context, not to class this context.

Related

cant access data return{} varibles in VueJS

function HeaderreRender() {
HeaderRender = false;
this.$nextTick(() => {
HeaderRender = true;
});
};
export default {
name: 'Home',
components: {
HeaderItem,
},
data: function() {
return {
HeaderRender: true,
};
}
}
this is the code now I want to use v-if="HeaderRender" to re-render the headerItem
but when I call function HeaderreRender()
it is replying to me
Uncaught ReferenceError: HeaderRender is not defined
on the function
any suggestions? on why this happens?
Try to place the HeadereRender() function within the methods object of the component and also, it's this.HeaderRender=true
In simple terms, this method does not know about the HeaderRender variable, thus it is not defined in the scope of the function, written that way

Way to proxy/override ServiceWorkerRegistration function

I'm trying to proxy the showNotification method of a ServiceWorkerRegistration object. Here's how I'm doing it right now:
function swNotificationCallback(title, opt) {
console.log("title", title);
console.log("options", opt);
return true
}
function createSWHandler(original) {
return (title, opt) => {
if (swNotificationCallback(title, opt)) {return original(title, opt)}
}
}
navigator.serviceWorker.getRegistrations().then(val => val.forEach(sw => {
if (!sw._showNotification) {
// backup the old just in case
sw._showNotification = sw.showNotification;
sw.showNotification = createSWHandler(sw.showNotification);
}
}));
Calling sw.showNotification correctly logs everything, but no notification is shown and this error is thrown:
Uncaught (in promise) TypeError: 'showNotification' called on an object that does not implement interface ServiceWorkerRegistration.
Any way to remedy this? I think it might be possible to use a Proxy but I'm not sure how one would go about reassigning the registered service worker.
You need to invoke the method on the instance, not as a plain function without context. Use call:
function createSWHandler(original) {
return function(title, opt) {
// ^^^^^^^^
if (swNotificationCallback(title, opt)) {
return original.call(this, title, opt)
// ^^^^^^^^^^^
}
}
}
Alternatively you could
createSWHandler(sw.showNotification.bind(sw))

VueJS how to use _.debounce on data changes

I'm building a little vue.js-application where I do some post requests. I use the watch-method to whach for api changes which then updates the component if the post request is successfull. Since the watcher constantly checks the API I want to add the ._debounce method but for some reason it doesn't work.
here is the code:
<script>
import _ from 'lodash'
export default {
data () {
return {
cds: [],
cdCount: ''
}
},
watch: {
cds() {
this.fetchAll()
}
},
methods: {
fetchAll: _.debounce(() => {
this.$http.get('/api/cds')
.then(response => {
this.cds = response.body
this.cdCount = response.body.length
})
})
},
created() {
this.fetchAll();
}
}
</script>
this gives me the error: Cannot read property 'get' of undefined
Can someone maybe tell me what I'm doing wrong?
EDIT
I removed the watch-method and tried to add
updated(): {
this.fetchAll()
}
with the result that the request runs in a loop :-/ When I remove the updated-lifecycle, the component does (of course) not react to api/array changes... I'm pretty clueless
Mind the this: () => { in methods make the this reference window and not the Vue instance.
Declare using a regular function:
methods: {
fetchAll: _.debounce(function () {
this.$http.get('/api/cds/add').then(response => {
this.cds = response.body
this.cdCount = response.body.length
})
})
},
Other problems
You have a cyclic dependency.
The fetchAll method is mutating the cds property (line this.cds = response.body) and the cds() watch is calling this.fetchAll(). As you can see, this leads to an infinite loop.
Solution: Stop the cycle by removing the fetchAll call from the watcher:
watch: {
cds() {
// this.fetchAll() // remove this
}
},

How to define function with usage context.log("My Log") and context.log.metric("MetricName", 123)

JavaScript experts!! I'm using the Node.js implementation of Azure functions, and I have a function something like the following:
module.exports = function (context, req) {
context.log("Item failing on XXX");
context.log.metric("XXX Failing", 1223);
}
Now, im in the process of doing some unit tests locally which requires me to mock the context. I'm struggling to figure out how the context.log is defined to work as both a function context.log() and a static object context.log.metric().
Any ideas?
Thanks
Paul
Thanks for the feedback, figured it out the next morning with a clear head.
newEventgridContext(doneCallback) {
var context = {
body: {
error: null
},
eventGridObject: {},
done: function () {
doneCallback(this);
},
bindings: {},
log: function (msg) {
console.log(msg)
}
}
context.log["error"] = function(msg){
console.error(msg)
}
context.log["metric"] = function(arg1, arg2){
...
}
return context
}
So now the usage context.log("Message") and context.log.metric("Count",12)

How do I test `image.onload` using jest in the context of redux actions (or other callbacks assigned in the action)

My problem was that I am trying to make a unit test for a function but can't figure out how to test a part of it.
This is a react / redux action that does the following:
1) retrieves json data with an image url
2) loads the image into an Image instance and dispatches its size to the reducer (asynchronously when image is loaded using Image.onload)
3) dispatches that the fetch was completed to the reducer
The image onload happens asynchronously, so when I try to unit test it it wouldn't be called. Moreover, I can't just mock things out because the image instance is created within the function...
Here's the code I wanted to test (removing some checks, branching logic, and stuff):
export function fetchInsuranceCardPhoto() {
return dispatch => {
dispatch(requestingInsuranceCardPhoto());
return fetch(`${api}`,
{
headers: {},
credentials: 'same-origin',
method: 'GET',
})
.then(response => {
switch (response.status) {
case 200:
return response.json()
.then(json => {
dispatch(receivedInsuranceCardPhoto(json));
})
}
});
};
}
function receivedInsuranceCardPhoto(json) {
return dispatch => {
const insuranceCardFrontImg = json.insuranceCardData.url_front;
const insuranceCardBackImg = json.insuranceCardData.url_back;
if (insuranceCardFrontImg) {
dispatch(storeImageSize(insuranceCardFrontImg, 'insuranceCardFront'));
}
return dispatch(receivedInsuranceCardPhotoSuccess(json));
};
}
function receivedInsuranceCardPhotoSuccess(json) {
const insuranceCardFrontImg = json.insuranceCardData.url_front;
const insuranceCardBackImg = json.insuranceCardData.url_back;
const insuranceCardId = json.insuranceCardData.id;
return {
type: RECEIVED_INSURANCE_CARD_PHOTO,
insuranceCardFrontImg,
insuranceCardBackImg,
insuranceCardId,
};
}
function storeImageSize(imgSrc, side) {
return dispatch => {
const img = new Image();
img.src = imgSrc;
img.onload = () => {
return dispatch({
type: STORE_CARD_IMAGE_SIZE,
side,
width: img.naturalWidth,
height: img.naturalHeight,
});
};
};
}
Notice in that last storeImageSize private function how there's an instance of Image created and an image.onload that is assigned to a function.
Now here's my test:
it('triggers RECEIVED_INSURANCE_CARD_PHOTO when 200 returned without data', async () => {
givenAPICallSucceedsWithData();
await store.dispatch(fetchInsuranceCardPhoto());
expectActionsToHaveBeenTriggered(
REQUESTING_INSURANCE_CARD_PHOTO,
RECEIVED_INSURANCE_CARD_PHOTO,
STORE_CARD_IMAGE_SIZE,
);
});
This test though will fail because the test finishes before the image.onload callback is called.
How can I force the image.onload callback to be called so that I can test that the `STORE_CARD_IMAGE_SIZE action gets broadcasted?
After some investigation, I found a very interesting javascript function that would solve my issue.
It is this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Here's how I used Object.defineProperty(...) to solve my issue:
describe('fetchInsuranceCardPhoto', () => {
let imageOnload = null;
/** Override Image global to save onload setting here so that I can trigger it manually in my test */
function trackImageOnload() {
Object.defineProperty(Image.prototype, 'onload', {
get: function () {
return this._onload;
},
set: function (fn) {
imageOnload = fn;
this._onload = fn;
},
});
}
it('triggers RECEIVED_INSURANCE_CARD_PHOTO when 200 returned with data', async () => {
trackImageOnload();
givenAPICallSucceedsWithData();
await store.dispatch(fetchInsuranceCardPhoto());
imageOnload();
expectActionsToHaveBeenTriggered(
REQUESTING_INSURANCE_CARD_PHOTO,
RECEIVED_INSURANCE_CARD_PHOTO,
STORE_CARD_IMAGE_SIZE,
);
});
What I did here was use define property to override the setter of any instance of Image. the setter would continue to get or set like normal but would also save the value (in this case a function) that was set to a variable in the scope of the unit test. After which, you can just run that function you captured before the verification step of your the test.
Gotchas
- configurable needs to be set
- note that defineProperty is a different function than defineProperties
- This is bad practice in real code.
- remember to use the prototype
Hope this post can help a dev in need!

Categories