onmessage in web workers can not access class variable - javascript

I am making multithreading file uploading .
when I access to Class variable in myWorker.onmessage, it shows error.
app.4c7f2a2a.js:32 Uncaught TypeError: Cannot read properties of undefined (reading 'length')
at a.onmessage
How can I solve this error ?
check my source code.
// queue.js
class Queue {
constructor() {
this.items = [];
this.size = -1;
}
sendChunk( chunkId) {
if (window.Worker) {
const myWorker = new Worker("/worker.js");
myWorker.postMessage([chunkId]);
myWorker.onmessage = function (e) {
console.log(e.data);
console.log(this.size); // <-- this make error
}
}
}
}
export default Queue;
// worker.js
onmessage = async function (e) {
const count = e.data[0];
const data = {
count: count,
local_time: new Date().toLocaleTimeString(),
};
fetch('/time', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
})
.then((response) => {
return response.json();
})
.then((data) => {
postMessage(JSON.stringify(data));
})
.catch((error) => {
console.error('Error:', error);
});
}
// main.js
import Queue from './queue';
const q = new Queue();
q.startQueue();
console.log(this.size); makes error.

this will be within the scope of the onmessage function. If you need to use the class variables within the callback of onmessage then, you can store this into some other variable like that in the example below and then access the members within.
// queue.js
class Queue {
constructor() {
this.items = [];
this.size = -1;
}
sendChunk( chunkId) {
if (window.Worker) {
const myWorker = new Worker("/worker.js");
myWorker.postMessage([chunkId]);
const that = this
myWorker.onmessage = function (e) {
console.log(e.data);
console.log(that.size);
}
}
}
}
export default Queue;

Related

The fetch code in onNewScanResult is executed more than once once a QR code has been scanned, and also updating database. How to stop it from running?

executing the fetch code in onNewScanResult multiplt time and hence updating the database accordingly................
initialization of qr scanner.........
this.html5QrcodeScanner = new Html5QrcodeScanner(
qrcodeRegionId,
config,
verbose
); ```Executing scanner when qrcode is scanned```
this.html5QrcodeScanner.render(
this.props.qrCodeSuccessCallback,
this.props.qrCodeErrorCallback
);
}
}
this is main qr code class........
class QrCode extends React.Component {
constructor() {
super();
this.state = {
decodedResults: [],
};
this.onNewScanResult = this.onNewScanResult.bind(this);
}
this is where the executing multiple time is happing.......
onNewScanResult(decodedText, decodedResult) {
`geting data from loacal storage as we saved data earlier in the process about acess level`
const qrRes = decodedText;
const obj = JSON.parse(qrRes);
const token = localStorage.getItem("user");
const userData = JSON.parse(token);
const username = userData[0].userId;
const accesslevel = userData[0].accessLevel;
const result = JSON.parse(qrRes);
const ele = result.ele_name;
const newdata = { ele, username, accesslevel };
const data = {
Element_detail: obj,
accessLevel: newdata.accesslevel,
};
const verifyUser = localStorage.getItem("accessLeveldetails");
const accessdetail = JSON.parse(verifyUser);
```checking is user is verified or not```......
`checking the acess level you can ignore the checking focus on fetch part`....
This particular part is we have to stop executing multiple time so database is only entered with one value
if (accessdetail.accessLevel === data.accessLevel) {
try { ``` this fetch is updating database with multiple entries```
fetch(
data.accessLevel === 20
? `/v0/all_elements_image`
: `/v0/${accessdetail.msg}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(obj),
}
).then((res) => {
console.log(res);
if (!res) {
throw res;
}
return res.json();
});
} catch (error) {
console.log("Error:", error);
}
} else {
alert("WRONG USER");
}
}
}

Javascript Class set private var on public function

can i set variables on the scope of the class to be used later?
example
class TestClass {
#key = '';
#reference = '';
#onReturn = () => {};
constructor({ key } = {}) {
this.#key = key || this.#key;
this.#onReturn = onReturn || this.#onReturn;
}
login(username, password) {
this.#submit(username, password);
};
#submit(username, password) {
fetch(
`/login/${this.#key}`,
)
.then(response => response.json())
.then((json) => {
this.#handleResponse(json);
})
};
#handleResponse(json) {
this.#reference = json.reference;
this.#onReturn();
};
token() {
console.log(this.#key, this.#reference); // "blabla", empty
};
};
const Test = new TestClass({ // initializing the class
key: 'blabla',
onReturn: tokenSubmit
});
const onLoginSubmit = () => {
Test.login(username, password); // running a fetch which will set a private var
};
const tokenSubmit = () => {
Test.token(); // private var returns empty
};
which has two public methods login and token
where the token should log the key and the reference
as a result i do get the key which was set on the constructor
but the reference which was set while handling a fetch returns empty
Following up on #vlaz's comment, try the following test code:
async function test() {
const Test = new TestClass({ key: 'blabla' }); // initializing the
class
await LoginModule.login({ username, password }); // running a fetch which will set a private var
LoginModule.token(); // private var returns empty
}
The addition of await waits for the fetch to complete before proceeding to the next line, calling LoginModule.token().
For this to work, you'll also need to modify #submit to return fetch's promise:
#submit({ username, password }) {
return fetch(
`/login/${this.#key}`,
)
.then(response => response.json())
.then((json) => {
this.#handleResponse({ json });
})
};

NodeJS unable to modify a class obj

this is my first post in this forum. So please forgive me the misstakes.
I want to write a NodeJS server which runs a WebSocket Server (npm ws module).
The NodeJS server contains also a Class Obj which i want to modify a funciton afterwards over the Websocket server.
My Problem is the modified functjion cant acces global variables.
Can someone help if there is a solution for this problem or why this happes because if you do this without the Websocket it works.
Here is the code:
Server code:
const WebSocket = require('ws');
// WebSocket Server
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
try {
message = JSON.parse(message);
if (message.type == "handler") {
handler.modify(message.data);
console.log("modifyed");
}
if (message.type == "func") {
handler.modify_func(message.data);
console.log("modifyed");
}
if (message.type == "run") {
eval(message.data);
}
}
catch (error) {
}
});
});
// Modifying class
class Handler {
constructor() {
this.functions = [];
}
modify(data) {
let temp_class = new Function('return ' + data)();
temp_class.functions.forEach(element => {
if (this.functions.indexOf(element) == -1) {
this.functions.push(element)
}
this[element] = temp_class[element];
});
}
modify_func(data) {
let temp_func = new Function('return ' + data)();
this[temp_func.name] = temp_func;
}
test_func_from_orginal() {
console.log("test_func_from_orginal says:");
console.log(test_val);
}
}
var test_val = "this is the global variable";
var handler = new Handler();
Client code:
const WebSocket = require('ws');
//WebSocket Client
var ws = new WebSocket('ws://localhost:8080');
ws.on('open', function open(event) {
// ws.send(JSON.stringify({ type: "handler", data: Handler.toString() }))
ws.send(JSON.stringify({ type: "func", data: test_func_from_func.toString() }))
console.log("open")
});
//Class Module
class Handler {
static get functions() {
return ["test"];
}
static test_func_from_class() {
console.log("test_func_from_class sayes:")
console.log(test_val);
}
}
function test_func_from_func() {
console.log("test_func_from_func sayes:")
console.log(test_val);
}
setTimeout(function () { ws.send(JSON.stringify({ type: "run", data: 'handler.test_func_from_orginal()' })) }, 1000);
// setTimeout(function () { ws.send(JSON.stringify({ type: "run", data: 'handler.test_func_from_class()' })) }, 1000);
setTimeout(function () { ws.send(JSON.stringify({ type: "run", data: 'handler.test_func_from_func()' })) }, 1000);
Ok, so this is what it's all about - a simple mistake. If you cut out all the websocket stuff (which is not really relevant here, as strings, and not contexts, got passed from and back anyway), you'll get this:
class ServerHandler {
constructor() {
this.functions = [];
}
modify(data) {
let temp_class = new Function('return ' + data)();
// not sure why not just `eval(data)` btw
temp_class.functions.forEach(funcName => {
if (this.functions.indexOf(funcName) == -1) {
this.functions.push(funcName)
}
this[funcName] = temp_class[funcName];
});
}
}
class ClientHandler {
static get functions() {
return ["test_func_from_class"];
// not "test" as in your example
// you actually don't even need this registry:
// all the static methods can be collected in runtime
}
static test_func_from_class() {
console.log("test_func_from_class sayes:")
console.log(test_val);
}
}
var test_val = 42;
var handler = new ServerHandler();
handler.modify(ClientHandler.toString());
eval(`handler.test_func_from_class()`); // 42
This all works fine, as there's no longer a mismatch between a name of method stored in static get functions ("test") and actual name of that method ("test_func_from_class"). The trick is that all the static functions created along with that temporary class are scoped the same way any other entity created in ServerHandler; that's how they 'see' that test_val.
But 'works' here is about mere possibility of this approach from technical perspective, and not about feasibility. Both new Function and eval with arbitrary input are very dangerous security holes - and they're left wide open here.
I found now a solution for my problem.
Server Code
const WebSocket = require('ws');
// WebSocket Server
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
message = JSON.parse(message);
try {
if (message.type == "run") {
eval(message.data);
}
if (message.type == "obj_handler") {
handler.modify(JSON.parse(message.data));
}
}
catch (error) {
console.log(error);
}
// console.log('received: %s', message);
});
ws.send('something');
});
class ServerHandler {
constructor() {
this.data = "hi";
}
modify(data) {
for (const func in data) {
this[func] = eval(data[func]);
}
}
}
var test_val = 42;
var handler = new ServerHandler();
Client Code:
const WebSocket = require('ws');
//WebSocket Client
try {
var ws = new WebSocket('ws://localhost:8080');
ws.on('open', function open(event) {
ws.send(JSON.stringify({ type: "obj_handler", data: update.convert() }))
});
}
catch (error) {
}
// Needed Update with 2 new Functions
update = {
func_test_global: () => {
console.log(test_val);
},
func_test_this: _ => {
console.log(this.data);
},
convert: function () {
let new_update = {};
for (const func in this) {
if (func != "convert")
new_update[func] = "" + this[func];
}
return JSON.stringify(new_update)
}
}
// setTimeout(function () { ws.send(JSON.stringify({ type: "run", data: 'handler.func_test_global()' })) }, 1000);
// setTimeout(function () { ws.send(JSON.stringify({ type: "run", data: 'handler.func_test_this()' })) }, 1000);

How do you pass variables to other JS modules with Fetch API?

A JavaScript app uses Web Audio API to create sounds from JSON data. I am fetching weather data, going through the JSON data and setting their properties to variables then using those variables to manipulate my application and create sounds. Each function in it's own JavaScript module script file. The main.js not shown here is the entry point to app.
A sample JSON that will get replaced with real weather data.
dummy-data.json
{
"weather": {
"temp": 4,
"rain": 1,
"wind": 1.2
}
}
The fetch API logic.
fetchWeather.js
import { manageData} from './manageScript.js';
const DUMMY = '../dummy-data.json';
const fetchWeather = () => {
fetch(DUMMY)
.then((res) => {
return res.json();
})
.then((data) => {
manageData(data); // attaches JSON weather properties to variables
})
.catch((error) => {
console.log(error);
});
};
export { fetchWeather };
Attaches the JSON data to variables.
manageScript.js
function manageData(data) {
let rain = data.weather.rain;
//let wind = data.weather.wind;
let rainProbability;
if (rain == 1) {
rainProbability = 1;
}
else {
rainProbability = 0;
}
return rainProbability; // not sure how to return the data....?
};
export { manageData };
I want the variables from manageData function above to work here
makeSynth.js
import { manageData } from './manageScript.js';
const createSynth = () => {
//Web Audio API stuff goes here to create sounds from the variables.
//How do I get the variables to work here. Code below does not work!
let soundOfRain = manageData().rainProbability;
console.log(soundOfRain);
};
You can achieve this by refactoring your promises into a async/await pattern then returning the result (a different method of dealing with promises). Also - your createSynth function should be calling fetchWeather, not manageScript
dummy-data.json
{
"weather": {
"temp": 4,
"rain": 1,
"wind": 1.2
}
}
manageScript.js
function manageData(data) {
let rain = data.weather.rain;
//let wind = data.weather.wind;
let rainProbability;
if (rain == 1) {
rainProbability = 1;
} else {
rainProbability = 0;
}
return rainProbability;
}
export { manageData };
fetchWeather.js
import { manageData } from "./manageScript.js";
const DUMMY = "../dummy-data.json";
// Use async/await to be able to return a variable out from the promise
const fetchWeather = async () => {
const raw = await fetch(DUMMY);
const json_data = await raw.json();
const rain = manageData(json_data);
// Now you should be able to return the variable back out of the function
return rain;
};
export { fetchWeather };
makeSynth.js
import { fetchWeather } from "./fetchWeather.js";
const createSynth = async () => {
//Web Audio API stuff goes here to create sounds from the variables.
//Need to call fetchWeather (which in turn will call manageData)
let soundOfRain = await fetchWeather();
console.log(soundOfRain);
};
createSynth();
// dummy-data.json
{
"weather": {
"temp": 4,
"rain": 1,
"wind": 1.2
}
}
// fetchWeather.js
import { getRainProbability } from './get-rain-probability.js'
import { createSynth } from './create-synth.js'
const DUMMY = '../dummy-data.json'
const fetchWeather = () => {
return fetch(DUMMY)
.then((res) => res.json())
.then((data) => {
createSynth({ rainProbability: getRainProbability(data) })
})
.catch((error) => {
console.log(error)
});
};
export { fetchWeather }
// get-rain-probability.js
function getRainProbability(data) {
let rain = data.weather.rain
let rainProbability;
if (rain == 1) {
rainProbability = 1;
}
else {
rainProbability = 0;
}
return rainProbability; // not sure how to return the data....?
};
// create-synth.js
const createSynth = ({ rainProbability }) => {
const soundOfRain = //WebAPI stuff for audio using `rainProbability`
console.log(soundOfRain);
};
export { createSynth }
You can add data as a property of manageData that would return this, and access it with manageData().data; :
fetchWeather.js
const fetchWeather = () => {
fetch(DUMMY)
.then(res => {
return res.json();
})
.then(data => {
manageData.data = data; // attaches JSON weather properties to variables
})
.catch(error => {
console.log(error);
});
};
manageScript.js
function manageData() {
// ...
return this;
}
makeSynth.js
let soundOfRain = manageData().data.rainProbability;

cannot read property of undefined when initialize state in react

I'm trying to make a forecast app with React and Flux. I fetch the data from Yahoo Weather API, and put the data to my store with a callback in jsonp request.Then in the View, I get the data (in componentDidMount())from store as a state and pass some properties of it to child components.
The data(this.state.store), which is a Object, has two properties, called condition and forecast.The problem is that if I want to pass the this.state.store.condition(or forecast) to the child, it says TypeError: Cannot read property 'condition' of undefined. But if I just try to access this.state.store(for example, console.log(this.state.store)), there is no error.
Also, if I try to access this.state.store.condition in a try-catch statement, and log the error when there is one, I do access the condition successfully with the console printed TypeError above mentioned.
Here is my codes:
store:
const CHANGE_EVENT = 'change';
let _app = {};
// create a city
function create(city, data) {
_app[city.toUpperCase()] = {
condition: data.condition,
forecast: data.forecast,
};
}
const AppStore = Object.assign({}, EventEmitter.prototype, {
getAll() {
return _app;
},
emitChange() {
this.emit(CHANGE_EVENT);
},
addChangeListener(callback) {
this.on(CHANGE_EVENT, callback);
},
removeChangeListener(callback) {
this.removeListener(CHANGE_EVENT, callback);
},
});
// register callback
AppDispatcher.register((action) => {
switch (action.actionType) {
case AppConstants.CREATE_CITY: {
create(action.city, action.data);
AppStore.emitChange();
break;
}
// other cases
default:
// noop
}
});
actions:
function callback(city, data) {
console.log(data);
const action = {
actionType: AppConstants.CREATE_CITY,
city,
data,
};
AppDispatcher.dispatch(action);
}
const AppActions = {
create(city) {
getDataFromAPI(city, callback);
},
};
utils:
function getDataFromAPI(query, callback) {
let data;
const url = `https://query.yahooapis.com/v1/public/yql?q=select * from weather.forecast where u='c' AND woeid in (select woeid from geo.places(1) where text="${query}")&format=json`;
superagent
.get(url)
.use(jsonp)
.end((err, res) => {
console.log(res.body.query.results.channel.item);
data = res.body.query.results.channel.item;
callback(query, data);
});
}
views:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
store: Store.getAll(),
currentCity: 'BEIJING',
};
this.onChange = this.onChange.bind(this);
this.getCurrentCity = this.getCurrentCity.bind(this);
}
componentWillMount() {
AppActions.create('BEIJING');
}
componentDidMount() {
Store.addChangeListener(this.onChange);
}
onChange() {
this.setState({ store: Store.getAll() });
}
getCurrentCity(city) {
this.setState({ currentCity: city.toUpperCase() });
}
componentWillUnmout() {
Store.removeChangeListener(this.onChange);
}
render() {
// For now, I have to do all of these to pass the condition to the child component
let condition;
let forecast;
let text;
let temp;
let currentWeatherCode;
let forecastWeatherCode = [];
let currentWeatherClassName;
let forecastWeatherClassName = [];
let date;
let forecastDate = [];
console.log(this.state.store[this.state.currentCity]);<--NO ERROR
// console.log(this.state.store[this.state.currentCity])<--UNDEFINED
// console.log(this.state.store[this.state.currentCity].condition);<--CANNOT READ PROPERTY
^
|
ERROR ON THIS 2 STATEMENTS
try {
condition = this.state.store[this.state.currentCity].condition;
forecast = this.state.store[this.state.currentCity].forecast;
text = condition.text.toUpperCase();
temp = condition.temp;
currentWeatherCode = condition.code;
currentWeatherClassName = setWeatherIcon(currentWeatherCode);
date = condition.date;
for (let i = 0; i < 6; i++) {
forecastWeatherCode.push(forecast[i].code);
forecastWeatherClassName.push(setWeatherIcon(forecastWeatherCode[i]));
forecastDate.push(forecast[i].date);
}
} catch (err) {
console.log(err);<--STILL ERROR, BUT I DO ACCESS THE PROP CONDITION IN THIS WAY
}
return (
<div>
<Today
city={this.state.currentCity}
weatherStatus={text}
tempreture={temp}
currentWeatherClassName={currentWeatherClassName}
date={date}
/>
</div>
);
}
}
ReactDOM.render(<App />, document.querySelector('#app'));
It seems to me that you are trying to access the this.state.store[this.state.currentCity] property before it is fetched from the remote API.
You could add some sort of indication that the data is still being fetched like this.
render() {
// For now, I have to do all of these to pass the condition to the child component
let condition;
let forecast;
let text;
let temp;
let currentWeatherCode;
let forecastWeatherCode = [];
let currentWeatherClassName;
let forecastWeatherClassName = [];
let date;
let forecastDate = [];
console.log(this.state.store[this.state.currentCity]);<--NO ERROR
if (!this.state.store.hasOwnProperty(this.state.currentCity)) {
return <div>Loading...</div>;
}
... the rest of your original code
}
When it is done loading the setState() method is invoked and render() is called again. The second time it will fall trough the if and run your code.

Categories

Resources