How to use function argument as part of variable? - javascript

This works
chrome.storage.local.get('sizePref', function(items) { // Get size preferences from storage
var sizePref2 = items.sizePref.tops; // Set size to a var
console.log("You can get this " + sizePref2)
});
However, when I try to make it a function
function getSize(itemSize) {
chrome.storage.local.get('sizePref', function(items) { // Get size preferences from storage
var sizePref = items.sizePref.itemSize;
return (sizePref);
});
}
var mySize = getSize(tops);
console.log("This size that u are looking for is " + mySize)
it says "tops" is undefined.

When the property name is in a variable, you use the bracket syntax. So, instead of this:
items.sizePref.itemSize
you use this:
items.sizePref[itemSize]
In addition, you cannot return a value synchronously from an async callback. That logic is just wrong. So, you can't make a function getSize() that will return the result. The result will not be available until some time LATER after getSize() already returns. You would have to either pass a callback into getSize() or have getSize() return a promise.
function getSize(itemSize) {
return new Promise(function(resolve) {
chrome.storage.local.get('sizePref', function(items) { // Get size preferences from storage
resolve(items.sizePref[itemSize]);
});
}
getSize("whatever").then(function(result) {
// code that uses the result here
});

If you are not familiar with promises (viz. unlikely) then you can use callbacks too. I personally think promises are a better way to solve your issue.
function getSize(itemSize, callback) {
chrome.storage.local.get('sizePref', function(items) {
// Get size preferences from storage
var sizePref = items.sizePref[itemSize]; //thanks #jfriend00
callback (sizePref); //thanks at #Kevin Friedheim
});
}
var mySize = getSize(tops, function (mySize) {
console.log("This size that u are looking for is " + mySize)
});

Related

running functions synchronously in firebase

I am trying to call a function to get a value from a 'subproduct' table and insert it in to another table. However the value which I am returning is not fetching the latest value from table and it is getting returned even before the snapshot part of the function is getting executed. I want it to run synchronously. Is there a better way in which it can be written.
function getGSTvalues(para1) {
var gstVar = 1;
var gstVarPromise = SubProductRef.once("value").then(function(snapshot) {
snapshot.forEach(function(child) {
if (para1 == child.val().subproductName) {
gstvar = child.val().gst;
console.log("InsidePromise" + gstVar);
}
});
console.log("outside fun : " + gstVar);
});
console.log("outside fun1 : " + gstVar);
return gstVar;
};
This is where I am calling the above function:
var gstans = getGSTvalues($('#edit_ProductSubType').val());
Any help would be appreciated
Using synchronous logic would be a big step backwards. The best solution here would be to use the asynchronous pattern correctly and provide a callback function to getGSTvalues() which is executed after the async operation completes and receives the result as an argument. Try this:
function getGSTvalues(para1, cb) {
var gstVar = 1;
var gstVarPromise = SubProductRef.once("value").then(function(snapshot) {
snapshot.forEach(function(child) {
if (para1 == child.val().subproductName) {
gstVar = child.val().gst;
}
});
cb && cb(gstVar);
});
};
getGSTvalues($('#edit_ProductSubType').val(), function(gst) {
console.log(gst);
// work with the value here...
});
Another alternative would be to return the promise from SubProductRef from getGSTvalues() and apply then() on that in the calling scope, although this would render the function largely redundant.
Also note that JS is case sensitive so gstVar is not the same as gstvar. I corrected this above.

Chrome Extension | Is there any way to make chrome.storage.local.get() return something?

in my chrome extension I need to use chrome storage. In my background script first I create an object and add it to chrome storage and then I want to get my object from there and to be returned. Something like that:
...
var obj = {};
chrome.storage.local.set(obj, function () { });
...
var data = getData(obj); // I want my object to be returned here
var returnedData = null;
function getData(obj) {
chrome.storage.local.get(obj, function(result) {
returnedData = result; // here it works, I can do something with my object
});
return returnedData; // here it doesn't work
}
As far as I understood from here chrome.storage.local.get is asynchronous with its consequences. But is there any way how to get something from chrome storage and make it to be returned? I mean maybe I should wrap chrome.storage.local.get in another function or so?
Many thanks in advance!
If you want to stay away from global variables and you're okay with modern browser requirements, then you can implement a native JavaScript Promise object. For example, here's a function that returns the stored data for a single given key:
function getData(sKey) {
return new Promise(function(resolve, reject) {
chrome.storage.local.get(sKey, function(items) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
reject(chrome.runtime.lastError.message);
} else {
resolve(items[sKey]);
}
});
});
}
// Sample usage given this data:
// { foo: 'bar' }
getData('foo').then(function(item) {
// Returns "bar"
console.log(item);
});
If you need support for IE11 and below, then you'll have to turn to a library like jQuery.
No it's not possible
But there are several ways around this problem
Do everything you want to do with the data returned from .get() inside the callback (or start it from there using function calls). This is what #wernersbacher posted
Take a look at deferreds (jQuery or Q libraries). A deferred's promise can be returned from getData. Inside the .get() callback, you can resolve the deferred. Outside of getData you can use .then() to do something after the deferred resolved
Something like this
function getData(obj) {
var deferred = $.Deferred();
chrome.storage.local.get(obj, function(result) {
deferred.resolve(result);
});
return deferred.promise();
}
$.when(getData(obj)).then(function(data) {
// data has value of result now
};
You have to do it like that:
var returnedData = null;
function setData(value) {
returnedData = value;
}
function getData(obj) {
chrome.storage.local.get(obj, function(result) {
setData(result); // here it works, I can do something with my object
});
return; // here it doesn't work
}
..because you tried to return a value which did not get read from storage yet, so it's null.
Update with Manifest V3 :
Now chrome.storage.local.get() function returns a promise that you can chain or can await in an async function.
const storageCache = { count: 0 };
// Asynchronously retrieve data from storage.local, then cache it.
const initStorageCache = chrome.storage.local.get().then((items) => {
// Copy the data retrieved from storage into storageCache.
Object.assign(storageCache, items);
});
Note : You must omit the callback paramter to get the promise.
Reference : https://developer.chrome.com/docs/extensions/reference/storage/#:~:text=to%20callback.-,get,-function
You need to handle it with callback functions. Here are two examples. You use a single function to set, however you create a separate function for each "On Complete". You could easily modify your callback to pass additional params all the way through to perform your needed task.
function setLocalStorage(key, val) {
var obj = {};
obj[key] = val;
chrome.storage.local.set(obj, function() {
console.log('Set: '+key+'='+obj[key]);
});
}
function getLocalStorage(key, callback) {
chrome.storage.local.get(key, function(items) {
callback(key, items[key]);
});
}
setLocalStorage('myFirstKeyName', 'My Keys Value Is FIRST!');
setLocalStorage('mySecondKeyName', 'My Keys Value Is SECOND!');
getLocalStorage('myFirstKeyName', CallbackA);
getLocalStorage('mySecondKeyName', CallbackB);
// Here are a couple example callback
// functions that get executed on the
// key/val being retrieved.
function CallbackA(key, val) {
console.log('Fired In CallbackA: '+key+'='+val);
}
function CallbackB(key, val) {
console.log('Fired In CallbackA: '+key+'='+val);
}

is it possible to return more than once in javascript function

my function delete data from store but at the same time i want to save the deletion time so i tried use return twice is right like i wrote in the function or it cause any problem later ? thank for help
function deleteStudent( $indexedDB, student, $scope, studentId, userId) {
return $indexedDB.openStore('student', function (store) {
student["delete_time"] = new Date().toISOString();
return saveItemInStore(store, student, userId);
return store.delete(studentId);
});
}
The only problem this will cause is that the second return statement will never execute.
Possibly you could re-write the return statement like this...
return (saveItemInStore(store, student, userId) && store.delete(studentId));
This will return "true" if both statements succeed. Additionally "store.delete" will not execute if "saveItemInStore" fails. You'll need to determine if this is appropriate for your situation.
Objects are tailor-made to allow you to return multiple pieces of information from a function. Just create as many properties as desired on a single object and return that object. Of course, the code that calls the function needs to know that that is what is being returned and use it accordingly.
var desiredInfo = myFunc();
document.write("<p>I learned both to " + desiredInfo.first + " and to " + desiredInfo.second + ".</p>");
function myFunc() {
var objToReturn = {};
var someAdvice = "buy low";
objToReturn.first = someAdvice;
var moreAdvice = "sell high";
objToReturn.second = moreAdvice;
return objToReturn;
}
Perhaps something like this fits your bill.
function mytestfunc(){
alert("I will be called first")
return (function(){
alert("I will be called second");
//saveItemInStore placeholder
return (function(){
alert("I will be called third")
//store.delete placeholder
})();
})();
}
mytestfunc();
Additionally, for reference check this stackoverflow question to know more about self executing functions.

Implementing callbacks in my own modules

I have an problem and I guess the solution is using callbacks. But I'm not sure how.
When starting node.js the following code gets called:
// create a new player and insert in the database
// the player gets inserted in the database correctly
var player1 = new player();
console.log(player1.id); // undefined
My constructor looks like this:
function Player(id) {
// if we don't have a id, this player needs to be created
this.id = (typeof id !== 'number') ? this.createPlayer() : this.setId(id);
}
Then I create a player in the database:
Player.prototype.createPlayer = function () {
var playerId = 0;
connection.query("INSERT INTO players SET `created_at` = now()", function (err, result) {
if (result) {
playerId = result.insertId;
console.log("Successfully inserted player no. " + playerId);
this.id = parseInt(playerId, 10);
return this.id;
} else {
console.log("Something went wrong: " + err);
}
});
};
My guess is I need some form of callback, but I'm not sure how I will do this. A small push in the right direction would be great!
This is the use case of node.js EventEmitter. You can use events to let the application know that your object initialization is completed and it is ready to be used. (I haven't tried the code, but its should work this way, let me know if it doesn't)
var EventEmitter = require('events').EventEmitter;
var util = require('util');
// Define your class like
function Player(id) {
// if we don't have a id, this player needs to be created
this.id = (typeof id !== 'number') ? this.createPlayer() : this.setId(id);
}
util.inherits(Player, EventEmitter);
Player.prototype.createPlayer = function (cb) {
connection.query(sql, function (err, result) {
if (result) {
// to avoid triggering event before binding.
process.nextTick(function () {
// success! passing null as first argument and data as second
this.emit('load', null, this.id);
});
} else {
process.nextTick(function () {
this.emit('load', err, null); // passing err as first argument
});
}
});
};
// And, use your class like
var player1 = new player();
player1.on('load', function (err, id) {
console.log(player1.id);
});
As per you comment, createPlayer is not always called, i.e. only on certain condition. so you could use the same emit in case where you don't want to call createPlayer.
Hope that helps
In Node.js there are a number of ways to queue up a callback function. They are all documented here: http://nodejs.org/api/timers.html#timers_setimmediate_callback_arg
One example for adding two numbers and passing the result to a callback would be:
function addWithCallback(a, b, callback) {
process.setImmediate(callback, a+b);
}
Just like that you could do:
addWithCallback(1,3,foo);
and foo would be queued into the event loop and passed the result of 1+3 at execution time. Also check out:
http://howtonode.org/understanding-process-next-tick and setImmediate vs. nextTick
Definitely a complete solution to your question, but hopefully the "small push in the right direction" you wanted :)
Basically a callback is just a function to call then something is done
ie
function asyncAdd(v1,v2,callback){
var total = v1 + v2;
callback(total);
}
asyncAdd(1,2,function(t){
alert(t);
});
Contrast this with:
syncAdd(v1,v2){
return total;
}
Hopefully this should give you enough to get started.
Much better explanation here: http://recurial.com/programming/understanding-callback-functions-in-javascript/

Async Function in Getter w/ Return in Callback

I want to define a read-only object property that asynchronously fetches a value and then returns it using the new EcmaScript 5 getters.
However, the property always returns undefined even though magicValue in the example code below is definitively never undefined. Also, when I just return 'xxx'; the printed value is still undefined. It only works when I return outside the callback function.
It seems like return is being executed immediately regardless of whether the callback of myAsyncFunction is called.
I am not sure whether this a bug in in V8 or if I am abusing JavaScript's getters.
Can I get this to work? I thought, since I can use getters and setters now, I will use getters/setters to read and write properties and regular functions to do certain tasks.
var User = function (id) {
this.id = id;
};
Object.defineProperty(User.prototype, 'magic', {
get : function () {
myAsyncFunction(function (magicValue) {
return magicValue;
});
}
});
var u = new User(5);
console.log(u.magic);
Prints undefined.
Asynchronous operations, these days, are typically handled with Promises. When you invoke your getter, it returns a promise, which you can attach a callback with using the 'then()' method.
Object.defineProperty(User.prototype, "magic", {
get: function() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(JSON.stringify({
magic: 'value'
}));
}, 1000);
});
}
});
Here is a working example:
https://jsfiddle.net/tw6gaudz/2/
Thanks #utkanos for your help.
JavaScript won't acynchronously return a getter function's value because getters are synchronous.
You could use a "setter":
var User = function (id) {
this.id = id;
};
Object.defineProperty(User.prototype, 'magic', {
set : function (value) {
setTimeout(value.bind(0, "hello"), 1000);
return true;
}
});
var a = new User(5);
a.magic = function(msg){
alert(msg);
};

Categories

Resources