can't get data from web worker - javascript

I have the following forEach:
hosts.forEach((host) => {
filterByHost(host);
});
as you can see the forEach call the following method where I pretend to use a web worker
function filterByHost(host) {
let sortedHost = [];
const filterHost = data.filter((element) => element.host.includes(host));
if (window.Worker) {
const worker = new Worker('utils.js');
worker.postMessage({ cmd: 'sortHost', filterHost });
worker.onmessage = function (event) {
switch (event.data.cmd) {
case 'sortHost':
servers = {
...servers,
[host]: event.data.data,
};
break;
default:
break;
}
};
}
}
the code inside my utils.js file is the following:
self.addEventListener(
'message',
function (event) {
switch (event.data.cmd) {
case 'uniqueHosts':
postMessage({ cmd: 'other', data: other(event.data.data) });
break;
case 'sortHost':
postMessage({
cmd: 'sortHost',
data: sortHost(event.data.filterHost),
});
break;
default:
break;
}
},
false
);
function other(data) {
return bla bla bla;
}
function sortHost(filterHost) {
return filterHost.sort((a, b) => {
if (a.apdex < b.apdex) {
return 1;
}
if (a.apdex > b.apdex) {
return -1;
}
return 0;
});
}
As you can see I trying to using a web worker in order to sort a big array of objects, and the worker works, it return a sorted array, but when I try to spread the results inside my servers I have and empty array, is like when the forEach call a the new Worker every thing is restarted and I can't find why

Related

Script create duplicate convensations Mongodb

I'm currently developing a conversation system with messages.
It checks if it has an active conversation ( hasConversation function) , and then determines what it should do.
If it has a conversation, then it shall only send a message, else create a conversation and then send message.
Anyway, it seems like something is wrong with my hasConversation function.
No matter what I do, it always creates two conversations, even if one exists.
It might also act like, if I call the function three times, it might create one,
then create another one, but then send the 3rd call message within the 2nd conversation.
What is wrong with my function?
It should check if both users are in a conversation.
function:
function hasConversation(userid,user2) {
return new Promise(function(resolve, reject) {
var x = [userid,user2];
var y = [user2, userid];
conversations.findOne( { members: {$all: x} }).then(function (conversation) {
// conversations.findOne({ members: x }).then(function (conversation) {
return resolve(conversation);
});
});
}
model:
var conversationsSchema = new Schema({
initiateduser : String,
name: {type:String, default: 'no name'},
members: { type: [String], default: []},
time: Number,
global: { type: Boolean, default: false},
gang: { type: Boolean, default: false},
});
a conversation is created by the following:
function createConversation(userid,user2,message) {
return new Promise(function(resolve, reject) {
var conv = new convensations();
conv.members = [userid, user2];
conv.initiateduser = userid;
conv.save(function (err,room) {
if (room._id) {
console.log("conv created, sending message");
createMessage(userid, room._id, message);
return resolve(room._id);
} else {
console.log(err);
return resolve(err);
}
});
});
}
example of calls:
Messages_model.sendNPCmessage('59312d2b329b7535b07e273c','testing','testshit?');
Messages_model.sendNPCmessage('59312d2b329b7535b07e273c','testing','testshit2?');
Messages_model.sendNPCmessage('59312d2b329b7535b07e273c','testing','testshit2?');
current output:
EDIT 1:
here is the main function calling it:
function sendNPCmessage(userid,from,message) {
console.log("checking npc conv");
return hasConversation(userid,from).then(function (haveconv) {
console.log("having conv? " + from);
console.log(haveconv);
if (haveconv) {
console.log("yes?");
return createMessage(from,haveconv._id,message).then(function (result) {
console.log("created mess?");
return result;
});
} else {
console.log("no?");
return createConversation(from,userid,message).then(function (result) {
console.log("created conv?");
return result;
});
}
});
}

Object properties are undefined, the object itself shows all the data though

I'm building an Single Page application for a minor project. I've been trying to save data from API call's to the Movie Database in an object. If i console.log the object, I can see all its properties and values. If I console.log the object.property, it returns 'undefined'. This is the code:
(() => {
"use strict"
/* Saving sections to variables
--------------------------------------------------------------*/
const movieList = document.getElementsByClassName('movie_list')[0];
const movieSingle = document.getElementsByClassName('movie_single')[0];
/* All standard filters for displaying movies
--------------------------------------------------------------*/
const allFilters = {
trending: 'movie/popular',
toplist: 'movie/top_rated',
latest: 'movie/now_playing',
upcoming: 'movie/upcoming'
};
const allData = {};
/* Initialize app - Get al standard data and save it in object
--------------------------------------------------------------*/
const app = {
init() {
getData(allFilters.trending, 'popular');
getData(allFilters.toplist, 'toplist');
getData(allFilters.latest, 'latest');
getData(allFilters.upcoming, 'upcoming');
this.startPage();
},
startPage() {
window.location.hash = "trending";
}
}
/* Function for getting data from the API
--------------------------------------------------------------*/
const getData = (filter, key) => {
const request = new XMLHttpRequest();
const apiKey = '?api_key=xxx';
const getUrl = `https://api.themoviedb.org/3/${filter}${apiKey}`;
request.open('GET', getUrl, true);
request.onload = () => {
if (request.status >= 200 && request.status < 400) {
let data = JSON.parse(request.responseText);
data.filter = key;
cleanData.init(data);
} else {
window.location.hash = 'random';
}
};
request.onerror = () => {
console.error('Error');
};
request.send();
};
/* Check if the data is list or single, and clean up
--------------------------------------------------------------*/
const cleanData = {
init(originalData) {
if (!originalData.results) {
this.single(originalData);
} else {
allData[originalData.filter] = originalData;
}
},
list(data) {
data.results.map(function(el) {
el.backdrop_path = `https://image.tmdb.org/t/p/w500/${el.backdrop_path}`;
});
let attributes = {
movie_image: {
src: function() {
return this.backdrop_path;
},
alt: function() {
return this.title;
}
},
title_url: {
href: function() {
return `#movie/${this.id}/${this.title}`;
}
}
}
showList(data.results, attributes);
},
single(data) {
data.poster_path = `https://image.tmdb.org/t/p/w500/${data.poster_path}`;
data.budget = formatCurrency(data.budget);
data.revenue = formatCurrency(data.revenue);
data.runtime = `${(data.runtime / 60).toFixed(1)} uur`;
data.imdb_id = `http://www.imdb.com/title/${data.imdb_id}`;
let attributes = {
movie_image: {
src: function() {
return this.poster_path;
},
alt: function() {
return this.title;
}
},
imdb_url: {
href: function() {
return this.imdb_id
}
},
similar_url: {
href: function() {
return `#movie/${this.id}/${this.title}/similar`
}
}
};
showSingle(data, attributes);
}
};
const showList = (cleanedData, attributes) => {
movieList.classList.remove('hidden');
movieSingle.classList.add('hidden');
Transparency.render(movieList, cleanedData, attributes);
};
const showSingle = (cleanedData, attributes) => {
movieSingle.classList.remove('hidden');
movieList.classList.add('hidden');
Transparency.render(movieSingle, cleanedData, attributes);
}
const formatCurrency = amount => {
amount = amount.toFixed(0).replace(/./g, function(c, i, a) {
return i && c !== "." && ((a.length - i) % 3 === 0) ? '.' + c : c;
});
return `€${amount},-`;
};
app.init();
console.log(allData); // Returns object with 4 properties: trending, toplist, latest & upcoming. Each property is filled with 20 results (movies with data) from the API.
console.log(allData.trending) // Returns 'undefined' (each property I've tried).
console.log(allData['trending']) // Returns 'undefined'
Object.keys(allData); // Returns an empty Array []
})();
When I use console.log(allData) I see 4 properties, all filled with the results from the API. But when i do console.log(allData.trending) or console.log(allData['trending']) it returns 'Undefined' in the console. Has anyone an idea how to fix this?
When you call app.init() it fires the init and sends the api call(s) to fetch data.
The call to fetch data is Asynchronous, which means it doesn't wait for the response to continue execution. So it goes ahead and executes next lines of code, which are your console.logs. At this time the API calls haven't responded with the data, so when you try to access data.property it fails as the data is not yet here.
When you do log(data) it creates a log of the reference to data, which gets updated in the log when the reference is filled with a value later. To get the value of data at that instance and prevent updating later you can try log(JSON.stringify(data)). When you do that you get a consistent result, none of your logs work, which is the actual behaviour.
To get your logs work, look into the success/load callback of you A(synchronous)JAX request, log it from there. Or if you constructed allData later in cleanData then call the logs after cleanData function.
So to answer your question, none of your logs should work as it is an asynchronous call. You are getting the allData logged due to the way console.log works with references that are updated later, use console.log(JSON.stringify(allData)) to get the actual snapshot of Object

optimize switch code to function args call

Im using the following code that working OK.
_handleIn: function(Filecontent, config) {
var oExtendedHTML = Filecontent;
switch (config.action) {
case 'new':
oExtended = this._crElement(Filecontent, config);
break;
case 'upd':
oExtended = this._updlement(oExtended, config);
break;
}
return oExtended;
},
Since I new to JS and I want to learn more I read that the switch sometimes can be change to this pseudo coe:
This
function actions(key, args){
switch(key){
case: 'foo':
return doFoo(args);
break;
case: 'bar':
return doBar(args);
break;
case: 'baz':
return doBaz(args);
break
}
}
var value = actions(keyargs);
// To This
var actions = {
foo: function doFoo(){...},
bar: function doBar(){...},
baz: function doBaz(){...}
};
var value = actions[key](args);.
my question is how can I change my code to this? not sure how to pass the key and args, Im using requirejs AMD module.
// your function without `switch`
var _handleInnerElement = {
_createElement: function(){
alert('create');
},
_updateElement: function(){
alert('update');
},
// you can use strings also
'new': function(fileContent, config) {
return this._createElement(fileContent, config);
},
upd: function(fileContent, config) {
return this._updateElement(fileContent, config);
}
}
// some variables to work with
var config = {
action: 'new',
some_data: 123
}
var someFileContent = {};
// usage
_handleInnerElement[config.action](someFileContent, config);

How to return templates from cache or ajax load?

In my code I try to load templates from cache. If template does not present in cache - load template from server by ajax. When loading is finished, I want to put template to cache and return it. Here is it:
var manager = function () {
return {
cache: [],
getTemplate: function (templateId) {
this.templateId = templateId;
if (this.cache[this.templateId]) {
return this.cache[this.templateId];
}
return this.loadTemplate();
},
loadTemplate: function() {
var
self = this;
$.get('/assets/templates/' + this.templateId + '.html', function (templateHtml) {
self.cache[self.templateId] = templateHtml;
return self.getTemplate(self.templateId);
});
}
}
}
var
manager = manager();
$('body').append( manager.getTemplate('template') );
I know that my code does not working because ajax request finished after function loadTemplate end. I think code can be fixed with deferred object but don't know how. Can anyone help me to find a solution?
There are two way of achieving your goal:
Promises (there are a lot of libs/shims). I'll rewrite it to ES6 just for the learning:
let manager = function () {
return {
cache: [],
getTemplate(id) {
let cache = this.cache;
return new Promise((resolve, reject) => {
if (cache[id]) {
resolve(cache[id]);
} else {
this.loadTemplate(id)
.then(template => {
cache[id] = template;
resolve(template);
})
.fail(reject);
}
});
},
loadTemplate(id) {
return $.get('/assets/templates/' + id + '.html');
}
}
};
let manager = manager();
manager.getTemplate('template').then((template) => {
$('body').append(template);
});
Callbacks:
let manager = function () {
return {
cache: [],
getTemplate(id, cb) {
let cache = this.cache;
if (cache[id]) {
cb(cache[id]);
} else {
this.loadTemplate(id)
.then(template => {
cache[id] = template;
cb(template);
});
}
},
loadTemplate(id) {
return $.get('/assets/templates/' + id + '.html');
}
}
};
let manager = manager();
manager.getTemplate('template', (template) => {
$('body').append(template);
});
Here's how you would do it, supporting all major browsers, and caching the requests too. This way you will only perform 1 request per template. (The other answers only cache the response).
var Manager = function() {
return {
cache: [],
getTemplate(id) {
var that = this;
if (that.cache[id] && that.cache[id].then){
console.log("Promise cache");
return that.cache[id]; //return promise from cache
}
return $.Deferred(function() {
var def = this;
if (that.cache[id]) {
console.log("Retrieved from cache!");
return def.resolve(that.cache[id]); //return cached template
}
that.cache[id] = def; //Cache promise
console.log("Retrieving template...");
that.loadTemplate(id).then(function(template) {
that.cache[id] = template;
def.resolve(template)
}).fail(function() {
def.reject();
});
return that.cache[id]; //return promise
}).promise();
},
loadTemplate(id) {
return $.get('https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js');
}
}
};
var manager = Manager();
manager.getTemplate('template').then(function(template){
console.log("loaded 1");
});
//This will use the promise from the first call (1 Request only)
manager.getTemplate('template').then(function(template){
console.log("loaded 2");
manager.getTemplate('template').then(function(template){
console.log("loaded 3"); //This will be retrieved fully from cache
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
As you are fetching the template via AJAX, you will be able to append the result only in AJAX success. So you need to pass the append logic as callback.Check the below code.
var manager = function () {
return {
cache: [],
getTemplate: function (templateId,callback) {
this.templateId = templateId;
if (this.cache[this.templateId]) {
callback(this.cache[this.templateId]);
}
this.loadTemplate(callback);
},
loadTemplate: function(callback) {
var
self = this;
$.get('/assets/templates/' + this.templateId + '.html', function (templateHtml) {
self.cache[self.templateId] = templateHtml;
callback(templateHtml)
});
}
}
}
var
manager = manager();
manager.getTemplate('template',function(result) {
$('body').append( result );
});
You may not need 2 functions to do this. So you can make it as one

Executing a function in a loop in javascript asynchronously- where to place defer.resolve?

I come from java/python background and new to javascript. I need to create a product list with the description of its children as well included in a jsonarray.
parent_list:
[{ children: [ 100714813, 100712694 ],
sp: '89.10',
weight: '1 ltr',
pack_type: 'Carton',
brand: 'Real',
p_desc: 'Fruit Power Juice - Orange' }]
Now for every parent I need to again iteratively fetch the children details by connecting to the database and finally have the result consolidated in a single jsonarray. But when I execute the below code, the control doesn't wait for fetching the children data( which makes sense as its being called asynchronously!), the result I get is a jsonarray that contains data only for the parents that have no children.
exports.productDetailsQuery = function(options) {
var AEROSPIKE_NAMESPACE = '';
var AEROSPIKE_SET = 'products';
var PD_KEY_VERSION_NUMBER = '1';
var defer = sails.Q.defer();
var results = options.results;
var parent_list = [];
var finalData = [];
var productKeys = results.map(
function(x){
return {
ns: AEROSPIKE_NAMESPACE,
set: AEROSPIKE_SET,
key: "pd.v" + PD_KEY_VERSION_NUMBER + '.' + 'c' + options.city_id + '.' + x.sku.toString()
}
}
);
var status = require('aerospike').status;
var breakException = {};
// Read the batch of products.
sails.aerospike.batchGet(productKeys, function (err, results) {
if (err.code === status.AEROSPIKE_OK) {
for (var i = 0; i < results.length; i++) {
switch (results[i].status) {
case status.AEROSPIKE_OK:
parent_list.push(results[i].record);
break;
case status.AEROSPIKE_ERR_RECORD_NOT_FOUND:
console.log("NOT_FOUND - ", results[i].keys);
break;
default:
console.log("ERR - %d - ", results[i].status, results[i].keys);
}
}
parent_list.forEach(function(parent){
var children = parent['children'];
console.log(children)
if(children){
var childKeys = children.map(function(child){
return {
ns: AEROSPIKE_NAMESPACE,
set: AEROSPIKE_SET,
key: "pd.v" + PD_KEY_VERSION_NUMBER + '.' + 'c' + options.city_id + '.' + child.toString()
}
});
sails.aerospike.batchGet(childKeys, function(err, childData){
if(err.code === status.AEROSPIKE_OK){
console.log('this called')
var entry = {};
entry['primary_prod'] = parent;
entry['variants'] = childData;
finalData.push(entry);
}
});
}
else{
var entry = {};
entry['primary_prod'] = parent;
finalData.push(entry);
}
});
defer.resolve(finalData);
} else {
defer.reject(err);
}
});
return defer.promise;
}
I need finalData to be like:
[{"primary_prod":{ children: [ 100714813, 100712694 ],
sp: '89.10',
weight: '1 ltr',
pack_type: 'Carton',
brand: 'Real',
p_desc: 'Fruit Power Juice - Orange' },
"variants":[{child_data},{child_data}]}, ...........]
Would really appreciate any help as to how to make it work.Is there a specific pattern to handle such cases?
Thanks!
What you have written is along the right lines but only the outer batchGet() is promisified. Because there's no attempt to promisify the inner batchGet(), it doesn't contribute to the finally returned promise.
Your overall pattern might be something like this ...
exports.productDetailsQuery = function(options) {
return sails.aerospike.batchGetAsync(...).then(results) {
var promises = results.filter(function(res) {
// Filter out any results that are not `AEROSPIKE_OK`
...
}).map(function(parent) {
// Map the filtered results to an array of promises
return sails.aerospike.batchGetAsync(...).then(function(childData) {
...
});
});
// Aggregate the array of promises into a single promise that will resolve when all the individual promises resolve, or will reject if any one of the individual promises rejects.
return sails.Q.all(promises);
});
}
... where batchGetAsync() is a promisified version of batchGet().
The fully fleshed-out the code will be longer but can be kept reasonably concise, and readable, by first defining a couple of utility functions. You might end up with something like this :
// utility function for making a "key" object
function makeKey(obj) {
return {
ns: '', //AEROSPIKE_NAMESPACE
set: 'products', //AEROSPIKE_SET
key: 'pd.v1.c' + options.city_id + '.' + obj.toString()
}
}
// promisified version of batchGet()
function batchGetAsync(obj) {
var defer = sails.Q.defer();
batchGet(obj, function(err, results) {
if(err.code === status.AEROSPIKE_OK) {
defer.resolve(results);
} else {
defer.reject(err);
}
});
return defer.promise;
}
var status = require('aerospike').status;
// Main routine
exports.productDetailsQuery = function(options) {
return batchGetAsync(options.results.map(makeKey)).then(results) {
var promises = results.filter(function(res) {
if (res.status === status.AEROSPIKE_OK) {
return true;
} else if(status.AEROSPIKE_ERR_RECORD_NOT_FOUND) {
console.log("NOT_FOUND - ", res.keys);
} else {
console.log("ERR - %d - ", res.status, res.keys);
}
return false;
}).map(function(parent) {
var entry = { 'primary_prod': parent },
children = parent['children'];
if(children) {
return batchGetAsync(children.map(makeKey)).then(function(childData) {
entry.variants = childData;
return entry;
});
} else {
return entry;
}
});
return sails.Q.all(promises);
});
}
With the new ES6 plus async stuff and babel its simpler. You can npm i -g babel npm i babel-runtime then compile and run the following with babel test.js --optional runtime --stage 2 | node:
import {inspect} from 'util';
let testData = [
{ id: 0, childIds: [1,2]},
{ id: 1, childIds:[] },
{ id: 2, childIds:[] }
];
function dbGet(ids) {
return new Promise( r=> {
r(ids.map((id) => { return testData[id];}));
});
}
async function getChildren(par) {
let children = await dbGet(par.childIds);
par.children = children;
}
async function getAll(parentIds) {
let parents = await dbGet(parentIds);
for (let p of parents) {
await getChildren(p);
}
return parents;
}
async function test() {
var results = await getAll([0]);
console.log(inspect(results,{depth:3}));
}
test().then(f=>{}).catch( e=> {console.log('e',e)});

Categories

Resources