require() not running synchronously? - javascript

I'm trying to load a module I created, and when it's loaded use some of it's methods. But it seems the code after the require gets executed before the require actually finishes.
Here is some code :
console.log(db);
var db = require('../../models')(true, v);
console.log(db);
Both console.log output undefined.
Here is the code inside ../../models :
module.exports = function(sync, v) {
if(sync === true && typeof v !== 'undefined') {
var db = null;
async.series([function(callback) {
require('../lib/db_connect.js').connect(require('../lib/config.js').vars.db, function(res) {
db = res;
callback();
});
}], function() {
return loadModels(db, v).models; // this returns the db instance with the models loaded
});
} else { /* other stuff */ }
});
However, I see the connection debug popping in the console some time after (so it gets loaded, just not synchronous). What am I doing wrong? async.series should return only when everything is finished? And most of all, not return undefined?

Related

how to get data outside javascript function

im wondering if i can get some help here, im not a skilled coder by far, but im trying to retrieve results outside the function and the result in log im getting is Undefined
var pricecrex;
getDataFromAPI("https://api.crex24.com/CryptoExchangeService/BotPublic/ReturnTicker?request=[NamePairs=BTC_WAGE]",
true,
function(data){
var resultcrex = JSON.parse(data);
if (resultcrex !== "undefined") {
if (resultcrex) {
var pricecrex = resultcrex.Tickers[0].Last
}
else {
msg.reply("0")
}
}
}
);
console.log(pricecrex);
It is because Ajax requests are async. console.log() gets executed before response is received from request, and thus before setting value in pricecrex. So you were getting undefined.
var pricecrex;
getDataFromAPI("https://api.crex24.com/CryptoExchangeService/BotPublic/ReturnTicker?request=[NamePairs=BTC_WAGE]",
true, function(data) {
var resultcrex = JSON.parse(data);
if (resultcrex !== "undefined") {
if (resultcrex) {
pricecrex = resultcrex.Tickers[0].Last;
print(pricecrex);
}
else {
msg.reply("0")
}
}
}
);
function print(data) {
console.log(data);
}
The nature of Javascript is continue running code once an asynchronous function has been started. So you run getDataFromAPI(), and then while that's running, the interpreter goes to the next piece of code, which is your console.log(pricecrex).
So you can either run the console.log(pricecrex) directly in the callback, function(data){}, or to keep things cleaner, wrap your console.log() within a function and call that function from within your callback.
Example:
let someVar;
someAsync('someurl.com', (data) =>{
someVar = data;
callTheConsole()
})
function callTheConsole(){
console.log(someVar)
}
Instead of assigning the value to the variable. Pass it to another function. Thus the value passed to another function is not 'undefined'.
function validation(pricecrex){
console.log(pricecrex);
}
getDataFromAPI("https://api.crex24.com/CryptoExchangeService/BotPublic/ReturnTicker?request=[NamePairs=BTC_WAGE]",
true,
function(data){
var resultcrex = JSON.parse(data);
if (resultcrex !== "undefined") {
if (resultcrex) {
var pricecrex = resultcrex.Tickers[0].Last;
validation(pricecrex);
}
else {
msg.reply("0")
}
}
}
);
For more information, check out the below link. Detailed information with examples is available.
How to return the response from an asynchronous call??

Using promise to work with web worker inside a JavaScript closure

I was executing an image processing operation in JavaScript which was working as expected expect one thing that sometimes it was freezing the UI, which made me to use Web worker to excute the image processing functions.
I have a scenario where i need to process multiple. Below is a summary of workflow which i am using to achieve the above feat.
//closure
var filter = (function(){
function process(args){
var promise = new Promise(function (resolve, reject) {
if (typeof (Worker) !== "undefined") {
if (typeof (imgWorker) == "undefined") {
imgWorker = new Worker("/processWorker.js");
}
imgWorker.postMessage(args);
imgWorker.onmessage = function (event) {
resolve(event.data);
};
} else {
reject("Sorry, your browser does not support Web Workers...");
}
});
return promise;
}
return {
process: function(args){
return process(args);
}
}
})();
function manipulate(args, callback){
filter.process(args).then(function(res){
callback(res);
});
}
Here, i am loading multiple images and passing them inside manipulate function.
The issue i am facing here in this scenario is that sometimes for few images Promise is not never resolved.
After debugging my code i figured out that it is because i am creating a Promise for an image while previous Promise was not resolved.
I need suggestions on how can i fix this issue, also i have another query should i use same closure(filter here in above scenario) multiple times or create new closure each time when required as below:
var filter = function(){
....
return function(){}
....
}
function manipulate(args, callback){
var abc = filter();
abc.process(args).then(function(res){
callback(res);
});
}
I hope my problem is clear, if not please comment.
A better approach would be to load your image processing Worker once only. during the start of your application or when it is needed.
After that, you can create a Promise only for the function you wish to call from the worker. In your case, filter can return a new Promise object every time that you post to the Worker. This promise object should only be resolved when a reply is received from the worker for the specific function call.
What is happening with your code is that, your promises are resolving even though the onmessage handler is handling a different message from the Worker. ie. if you post 2 times to the worker. if the second post returns a message it automatically resolves both of your promise objects.
I created a worker encapsulation here Orc.js. Although it may not work out of the box due to the fact i haven't cleaned it of some dependencies i built into it. Feel free to use the methods i applied.
Additional:
You will need to map your post and onmessage to your promises. this will require you to modify your Worker code as well.
//
let generateID = function(args){
//generate an ID from your args. or find a unique way to distinguish your promises.
return id;
}
let promises = {}
// you can add this object to your filter object if you like. but i placed it here temporarily
//closure
var filter = (function(){
function process(args){
let id = generateID(args)
promises[id] = {}
promises[id].promise = new Promise(function (resolve, reject) {
if (typeof (Worker) !== "undefined") {
if (typeof (imgWorker) == "undefined") {
imgWorker = new Worker("/processWorker.js");
imgWorker.onmessage = function (event) {
let id = generateID(event.data.args) //let your worker return the args so you can check the id of the promise you created.
// resolve only the promise that you need to resolve
promises[id].resolve(event.data);
}
// you dont need to keep assigning a function to the onmessage.
}
imgWorker.postMessage(args);
// you can save all relevant things in your object.
promises[id].resolve = resolve
promises[id].reject = reject
promises[id].args = args
} else {
reject("Sorry, your browser does not support Web Workers...");
}
});
//return the relevant promise
return promises[id].promise;
}
return {
process: function(args){
return process(args);
}
}
})();
function manipulate(args, callback){
filter.process(args).then(function(res){
callback(res);
});
}
typescirpt equivalent on gist:
Combining answers from "Webworker without external files"
you can add functions to worker scope like the line `(${sanitizeThis.toString()})(this);,` inside Blob constructing array.
There are some problems regarding resolving promise outside of the promise enclosure, mainly about error catching and stack traces, I didn't bother because it works perfectly fine for me right now.
// https://stackoverflow.com/a/37154736/3142238
function sanitizeThis(self){
// #ts-ignore
// console.assert(this === self, "this is not self", this, self);
// 'this' is undefined
"use strict";
var current = self;
var keepProperties = [
// Required
'Object', 'Function', 'Infinity', 'NaN',
'undefined', 'caches', 'TEMPORARY', 'PERSISTENT',
"addEventListener", "onmessage",
// Optional, but trivial to get back
'Array', 'Boolean', 'Number', 'String', 'Symbol',
// Optional
'Map', 'Math', 'Set',
"console",
];
do{
Object.getOwnPropertyNames(
current
).forEach(function(name){
if(keepProperties.indexOf(name) === -1){
delete current[name];
}
});
current = Object.getPrototypeOf(current);
} while(current !== Object.prototype);
}
/*
https://hacks.mozilla.org/2015/07/how-fast-are-web-workers/
https://developers.google.com/protocol-buffers/docs/overview
*/
class WorkerWrapper
{
worker;
stored_resolves = new Map();
constructor(func){
let blob = new Blob([
`"use strict";`,
"const _postMessage = postMessage;",
`(${sanitizeThis.toString()})(this);`,
`const func = ${func.toString()};`,
"(", function(){
// self.onmessage = (e) => {
addEventListener("message", (e) => {
_postMessage({
id: e.data.id,
data: func(e.data.data)
});
})
}.toString(), ")()"
], {
type: "application/javascript"
});
let url = URL.createObjectURL(blob);
this.worker = new Worker(url);
URL.revokeObjectURL(url);
this.worker.onmessage = (e) => {
let { id, data } = e.data;
let resolve = this.stored_resolves.get(id);
this.stored_resolves.delete(id);
if(resolve){
resolve(data);
} else{
console.error("invalid id in message returned by worker")
}
}
}
terminate(){
this.worker.terminate();
}
count = 0;
postMessage(arg){
let id = ++this.count;
return new Promise((res, rej) => {
this.stored_resolves.set(id, res);
this.worker.postMessage({
id,
data: arg
});
})
}
}
// usage
let worker = new WorkerWrapper(
(d) => { return d + d; }
);
worker.postMessage("HEY").then((e) => {
console.log(e); // HEYHEY
})
worker.postMessage("HELLO WORLD").then((f) => {
console.log(f); // HELLO WORLDHELLO WORLD
})
let worker2 = new WorkerWrapper(
(abc) => {
// you can insert anything here,
// just be aware of whether variables/functions are in scope or not
return(
{
"HEY": abc,
[abc]: "HELLO WORLD" // this particular line will fail with babel
// error "ReferenceError: _defineProperty is not defined",
}
);
}
);
worker2.postMessage("HELLO WORLD").then((f) => {
console.log(f);
/*
{
"HEY": "HELLO WORLD",
"HELLO WORLD": "HELLO WORLD"
}
*/
})
/*
observe how the output maybe out of order because
web worker is true async
*/

NodeJS - Writing to File Sometimes Finishes

I have an electron app and in it, I'm writing to a file.
if( fs.existsSync(envFilepath) ) {
envFile = fs.createWriteStream(envFilepath)
var envs = document.getElementById("envs").value.split(",")
envs.forEach( function(env) {
if( env && env.localeCompare(" ") !== 0 ) {
env = env.trim()
envFile.write(env + '\n')
}
})
envFile.end()
envFile.on('finish', function syncConfigs() {
//perform additional tasks
})
}
Sometimes, the array envs has elements and it will write. For those moments, end() is called and finish event is caught and I roll along smoothly. However, sometimes, envs could be empty and I don't write to the file. NodeJS seems to hang because I didn't call a write() and the finish event never gets called.
Why is this happening? Is there a workaround for this situation?
If you use fs.createWriteStream() you should listen for the 'close' event not the 'finish' event.
envFile.on('close', () => {
// handle done writing
})
You can work-around your issue by just not opening the file if you don't have anything to write to it. And, if you just collect all your data to write, it's both more efficient to write it all at once and simpler to know in advance if you actually have anything to write so you can avoid even opening the file if there's nothing to write:
if( fs.existsSync(envFilepath) ) {
function additionalTasks() {
// perform additional tasks after data is written
}
// get data to be written
let envs = document.getElementById("envs").value.split(",");
let data = envs.map(function(env) {
if( env && env.localeCompare(" ") !== 0 ) {
return env.trim() + '\n';
} else {
return "";
}
}).join("");
// if there is data to be written, write it
if (data.length) {
fs.writeFile(envFilePath, data, function(err) {
if (err) {
// deal with errors here
} else {
additionalTasks();
}
});
} else {
// there was no file to write so just go right to the additional tasks
// but do this asynchronously so it is consistently done asynchronously
process.nextTick(additionalTasks);
}
}

Parse function time out management

In Parse Cloud Code there is a response time limit of 15s. We've been experiencing problems on certain requests that depend on external service requests.
If we have 4 promises, promise 1 & 2 create objects but if the request "runs out of time" on promise 3 we need to destroy whatever was created on the process. I'm cascading the error handling in a similar way as the following example:
var obj1, obj2, obj3;
query.find().then(function() {
obj1 = new Parse.Object('Anything');
return obj1.save();
}).then(function() {
obj2 = new Parse.Object('Anything');
return obj2.save();
}).then(function _success() {
obj3 = new Parse.Object('Anything');
return obj3.save();
}).then(function _success() {
response.success();
}, function _error(err) {
var errorPromises = [];
if (obj1 != undefined) errorPromises.push(deleteExternalStuff(obj1.id));
if (obj2 != undefined) errorPromises.push(deleteExternalStuff(obj2.id));
if (obj3 != undefined) errorPromises.push(deleteExternalStuff(obj3.id));
Parse.Promise.when(errorPromises).then(function _success() {
response.error();
}, function _error() {
response.error(err);
});
});
The deleteExternalStuff function makes a get request on one of the object's id and then returns an object.destroy() promise.
My problem is that the get query works but the destroy promises inside the deleteExternalStuff are not deleting the objects from the database. Any suggestions on how to handle this case?
EDIT:
I've tested and whenever a timeout occurs, the error IS INDEED executed but the destroy() is what is not working just right.
EDIT 2: Added a similar structure for the deleteExternalStuff function
function deleteExternalStuff(objectId) {
var query = Parse.Query('Another Object');
query.equalTo('objXXX', objectId);
return query.find().then(function _success(anotherBunchOfObjects) {
var deletePromises = _.map(anotherBunchOfObjects, function(obj) {
return obj.destroy();
});
return Parse.Promise.when(deletePromises);
}, function _error(error) {
console.log(error); // **ERROR LOG**
return Parse.Promise.as();
});
}
EDIT 3:
With further testing I added an error handler in deleteExternalStuff function and printed to log... Apparently the **ERROR LOG** prints the following: {"code":124,"message":"Request timed out"}
This makes me think that Parse doesn't permit the use of chained promises in error handling if you have already reached the timeout limit... :\
Suggestions for alternate solutions are appreciated.
To make sure all objects are deleted before your request is finished, you will have to wait until all promises are resolved:
var promises = [];
if (obj1 != undefined) promises.push(deleteExternalStuff(obj1.id));
if (obj2 != undefined) promises.push(deleteExternalStuff(obj2.id));
if (obj3 != undefined) promises.push(deleteExternalStuff(obj3.id));
Promise.all(promises).then(function() {
response.error(err);
});

Object property always undefined

This is the first time I've used JS objects and I'm confused as to why this property is always undefined:
function Rotator() {
this.interval = 300;
this.image = 0;
this.images = undefined;
}
Rotator.prototype.Fetch = function(links) {
console.log("Fetch called");
this.images = links;
}
Rotator.prototype.Current = function() {
if (this.images == undefined) {
console.log("Error, images is undefined");
}
return this.images[this.image];
}
r = new Rotator;
$.getJSON("./data.php", function (data) {
r.Fetch(data.images);
});
console.log(r.Current());
The error I get is:
Uncaught TypeError: Cannot read property '0' of undefined
The JSON returned is working fine, and fetch is marked as called in the console (when logged the data is fine as well). Why is Rotator.images always undefined?
Edit: Some console.log results:
Logging data.images in $.getJSON results in correct data.
Logging links in Fetch results in correct data.
Logging this.images in Fetch results in correct data.
Logging this.images in Current results in null.
Because getting JSON is asynchronous, that's why the data is only available in the callback function.
$.getJSON("./data.php", function (data) { // callback function
r.Fetch(data.images); // this will run when the data is available
});
console.log(r.Current()); // this will run immediately -> data.images is null
Everything that depends on the data should be placed in the callback function!
Will this get me purists on my neck or is it acceptable?
Rotator.prototype.Current = function() {
if (this.images) return this.images[this.image];
console.log("Error, images is undefined, null, empty or 0");
}
You can't use undefined that way. Use null instead:
this.images = null;
and
if (this.images == null) {
Edit:
You also have to avoid using the images property if it's null:
Rotator.prototype.Current = function() {
if (this.images == null) {
console.log("Error, images is undefined");
return null;
}
return this.images[this.image];
}

Categories

Resources