I've a question about subsequent function calls or somehow. I've this code here:
let socket = new WebSocket("localhost:8181");
socket.subscribe("abc").bind("test", function (response) {
console.log(response);
});
subscribe(channel) {
//Here I do some things
return this;
}
bind(eventName, callback) {
//Here I need the "abc" value
}
Currently I'm calling a second function after another to first subscribe something and then bind it. The problem is that I need the value passed to the subscribe function in the following bind function.
Currently I'm returning this because otherwise .bind() would be undefined because of the scope bla bla so because of this I can't just return the channel. Does someone has an idea how I can get this done without changing the function call structure?
You can't return this and also pass a variable. I think your best bet may be wrap your subscribe call in a closure so that you can keep local state.
function createAndSubscribe(abc) {
// You can create other local variables here
let otherLocal = 'foo';
let socket = new WebSocket("localhost:8181");
socket.subscribe(abc).bind("test", function (response) {
// Use abc or foo here
});
}
createAndSubscribe('abc');
Every time you call the function createAndSubscribe, it creates a unique closure that holds the value of abc and any other variables that you create.
Related
$(function(){
var astronautsData;
$.getJSON('http://api.open-notify.org/astros.json', doSomething);
function doSomething(data) {
astronautsData = data;
}
alert(astronautsData.people[0].name)
});
I would like to be able to use the data in every function I make, that's why I tried to put it in the variable astronautsData, but unfortunately astronautsdata is undefined.
You can access astronautsData inside doSomething.your alert() will get executed
before getJSON. that's why you are getting undefined.
$(function(){
var astronautsData;
$.getJSON('http://api.open-notify.org/astros.json', doSomething);
function doSomething(data) {
astronautsData = data;
alert(astronautsData.people[0].name)
}
});
Here you must understand one thing that getJSON is 'async'. Your alert method trying to show the data which gonna come in future. In order to solve this problem, you must use 'then', 'done' or 'fail' like below.
$(function(){
var astronautsData;
//Assign your getjson request
var jsonRequest = $.getJSON('http://api.open-notify.org/astros.json');
//This function runs once the getJSON method is success
jsonRequest.done(function(data){
astronautsData = data;
});
//This function runs after the success of getJSON
jsonRequest.then(function(){
//Here you have to do your alert ( This alert will give data )
alert(astronautsData);
});
//This alert will give undefined value as this line of code and getjson request runs parallelly
alert(astronautsData);
});
Your .getJSON is asynchronous.
Try using a Promise to wait for your call to be done :
prom = new Promise((resolve, reject) => {
$.getJSON('http://api.open-notify.org/astros.json', function(){
astronautsData = data;
resolve('Ajax done');
});
});
prom.then((successMessage) => {
console.log(successMessage);
alert(astronautsData.people[0].name)
});
Exposing variables in window/global scope is bad in my opinion. You should wrap it in a function (like a class of sorts) and expose it like this:
function Values(type) {
this.value1 = "something";
}
From this point you can use prototype to define additional functions on "Values" like so:
Values.prototype.doStuff = function() {
return this.value1 + ' addsomething';
};
Inside of the prototype function you can define/return promises or do whatever you want including assigning values to the instance. You can also assign the instance to a global variable to make it a singleton of sorts. Granted your still using a global variable for that but its the instance of Values assigned to the variable not the actual values that are stored.
This is a bit of an over simplification perhaps, but in a way this is how the global variables for lodash or jquery work, although they have a LOT more going on to check for existing global variables and such before attempting to define it on global scope as typically you want to avoid that.
you can use var at global scope (outside of all functions) to declare a global variable:
<script>
var astronautsData;
$(function(){
$.getJSON('http://api.open-notify.org/astros.json', doSomething);
function doSomething(data) {
astronautsData = data;
}
alert(astronautsData.people[0].name)
});
</script>
use global.astronautsData if you want it to be global
i want to pass value to chrome.storage.sync.get() function.
chrome.storage.sync.get('privateKey', function(data, e) {
if (data.privateKey) {
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(data.privateKey);
var uncrypted = decrypt.decrypt(e.detail.encryptedVal)
alert(uncrypted);
} else {
alert("key is not set");
}
});
but e.detail.encryptedVal is showing me as undefined.
The callback of .get() expects exactly 1 parameter.
By passing a function that takes 2 parameters (i.e. function(data, e) {...}), you do the following:
The function is called with one parameter. It is assigned to a callback-local variable data.
The second parameter stays undefined. It is assigned to a callback-local variable e.
If there was a variable e in the outer scope, it is no longer accessible.
I assume the part 3 is exactly your problem. You had a variable e in the scope where you called .get(), but you made it inaccessible.
Generally, due to the concept called closures, you don't actually need to pass e inside the scope - you just use the variable from the outer scope, and it will be retained in memory until the function executes. Think of it as a "locally global" variable, if that makes any sense. If it doesn't, there are better explanations.
With that in mind:
chrome.storage.sync.get('privateKey', function(data) { // just don't mention e here
/* ... */
// Just use e inside if it comes from outer scope
var uncrypted = decrypt.decrypt(e.detail.encryptedVal);
/* ... */
});
Better yet, let's make that into a function:
function decryptValue(value, callback) {
chrome.storage.sync.get('privateKey', function(data) {
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(data.privateKey);
var decrypted = decrypt.decrypt(value);
callback(decrypted);
}
}
/* ... */
decryptValue(e.detail.encryptedVal, function(decrypted) {
// Do something
});
/* ... */
Note that callback variable? While you can use decrypted inside the callback of .get(), due to the fact it's asynchronous you can't use it outside. There is a very good overview of the problem, and another one here. Basically, .get() is asynchronous so you HAVE to use a callback.
/* ... */
decryptValue(e.detail.encryptedVal, function(decrypted) {
// Do something with decrypted
});
// Here, decrypted is not yet computed
/* ... */
Most of Chrome API is asynchronous. I would recommend to read You Don't Know JS book on the topic.
So, from the comments bellow, I suppose you'd like to pass the value to get callback in order to user it in the callback. Unfortunately, this can't be done the way you want it to be done. But, what you can do is write a decrypt function that will take the encryptedVal as an argument, and simply use it
function decrypt(encryptedVal) {
chrome.storage.sync.get('privateKey', function (data) {
if (data.privateKey) {
var decrypt = new JSEncrypt();
decrypt.setPrivateKey(data.privateKey);
var uncrypted = decrypt.decrypt(encryptedVal)
alert(uncrypted);
} else {
alert("key is not set");
}
});
}
Do note that this function uses asynchronous code and you may not return from it as you'd expect.
So, I have a script that fetches data from a SQL database and I'm trying to build a JS wrapper for it. I'm using the following functions to call that script and use information from the DB as soon as it's ready.
var User = function() {
this.email = null;
//Async call to get user values
this.current(function(response) {
this.email = response.email;
//The value is assigned/usable at this point
});
};
User.prototype.current = function(callback) {
$.post("php/db_functions.php", {object: "CurrentUser"}).done(function(result) {
callback(JSON.parse(result)[0]);
});
};.
Everything seems to work fine, but if I try to access the value from the object after I've created it, it returns undefined, like so:
var me = new User();
//And then, way after the async call and when me.email should be defined
me.email //Returns undefined
Why can I use it in the callback, but not afterwards?
In a function, the context variable this points to either the global window object or to undefined in the strict mode, unless specified otherwise by the caller. Therefore, you need to either capture the value of this in a local variable:
//Async call to get user values
var that = this;
this.current(function(response) {
that.email = response.email;
});
or call the function in the desired context using either the call or the apply method:
User.prototype.current = function(callback) {
var that = this;
$.post("php/db_functions.php", {object: "CurrentUser"}).done(function(result) {
callback.call(that, JSON.parse(result)[0]);
});
};.
Also, as others have mentioned, there is no guarantee the AJAX request will have finished by the time the User contructor returns.
This is a timing bug since the variable is not assigned until the async call returns. You can't access email right away.
I passed a function(which itself has a parameter let's say para) as a parameter into another function function b() and how to get the parameter para.
here is the simple example
<input type="button" onclick="sometest3()" value="Run test">
<script>
function sometest3() {
// pass an anonymous function as a parameter which has
// its own parameter "client"
sometest('connection',function(client){client.getInfo();})
}
function sometest(eve,func) {
// get this function's parameter which is "client" and pass
// a reference of sometest2 to it. so in the callback I can use
client.getInfo();
}
function sometest2() {
this.getInfo=function (){alert("get it");};
}
</script>
You can't given the code you've posted. The anonymous function passed to sometest is held as a local variable that is inaccessible to functions outside its scope.
If you want sometest to access client, you must pass it, the following uses local variable:
function sometest3() {
var client = {getInfo: function(){ /* whatever */}};
sometest('connection', function(client){client.getInfo();}, client);
}
function sometest(eve, func, client) {
// The client object has been passed from sometest3
func(client);
}
Or you could make it available to both functions in a closure or global variable, or property of some object accessable to both functions (essentially these same thing). Your choice.
e.g. using a closure:
var foo = (function() {
var client = {getInfo: function(){ /* whatever */}};
return {
sometest3: function() {
foo.sometest('connection', function(obj){obj.getInfo();}, client);
},
sometest: function(eve, func, client) {
// The client object has been passed from sometest3
func(client);
}
};
}());
Then call it as foo.sometest3().
Edit
Added call
If you want to know how many arguments are named in a function func you can check func.length. And this doesn't mean that you can't pass more or less arguments to that function, of course, but only how many of them are stored in local scoped variables.
But if you want to know the names of those variables the best thing to do is to convert the function to a string and get its declaration:
var parms = String(func)
.match(/function[^\(]*\(([^\)]*)/)[1]
.split(/\s*,\s*/);
(Mind you that putting comments between the function keyword and its declaration may mess up this method.)
That being said, I fail to see how this can be useful for you...
In my code I need to call an object method, retrieve the data from its callback, and pass it to another method or function.
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
doAwesomeStuff(data);
}
);
However, the callback does not recognize any functions/objects/variables outside its scope.
What I've tried to do right now is wrap everything around a function.
var myData = '';
(function(myData) {
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
myData = data;
}
);
});
doAwesomeStuff(myData);
However that doesn't work either.
Anybody know how to properly accomplish this?
You haven't really given us enough to go on there, but this statement:
However, the callback does not recognize any functions/objects/variables outside its scope.
...is incorrect. A function has access to everything in scope where it's defined, so for instance:
var a = 10;
function foo(b) {
bar(5);
function bar(c) {
alert(a + b + c);
}
}
foo(12); // alerts "27"
Note how bar had access not only to c, but also to b (from the call to foo) and a (from the outermost scope shown).
So in your example, the anonymous function you're passing in as the callback has access to everything that's in scope where it's defined; doAwesomeStuff having been defined elsewhere presumably has access to different information, so you'll have to have the callback pass it any data it needs.
So I'm guessing your code looks something like this:
function doAwesomeStuff(data) {
// ...
}
function doSomethingNifty() {
var a = 10,
b = 20;
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
doAwesomeStuff(data);
}
);
}
...and you want doAwesomeStuff to have access to a and b from the call to doSomethingNifty. If so, your only options are to pass them into it as arguments (probably best) or export them to variables some scope that doSomethingNifty and doAwesomeStuff share (probably not ideal, too much like globals).
You can bind required variables to the function passed into the async method.
Also, this SO question has a good treatment of the topic.
Your second version is not going to work at all, since you are trying to immediately access the data that are not yet available (not until the callback has been invoked.)
Your first method:
someObject.getSomeData({option1:'value1', option2:'value2'},
function(data) {
doAwesomeStuff(data);
}
);
looks fine. Please provide more details on what is not working.
One problem could be that getSomeData() does not actually call the callback function.
doAwesomeStuff() can modify many different variables from the received data. The variables which can be accessed by doAwesomeStuff() are those that were available to it (in its scope) where it was created..