I am learning about localStorage and it sounds like each browser gives a domain 5MB.
I wrote this code to cache the data returned from an ajax call and it works. But how do I test to see if localStorage is full? If there is no localStorage space available I imagine that the ajax request should be made again.
Here's my code:
if ( localStorage && localStorage.getItem('myGithub') ) {
console.log('if statement');
console.log( JSON.parse( localStorage.getItem( 'myGithub') ) );
render( JSON.parse( localStorage.getItem( 'myGithub') ) );
}
else {
console.log('else statment');
$.ajax({
url : 'https://api.github.com/users/xxxxxxxxx',
dataType : 'json',
success : function (data) {
if ( localStorage ) {
localStorage.setItem( 'myGithub', JSON.stringify(data) );
}
console.log(data);
render(data);
}
});
}
//Render method for printing the results to the <body> element.
//Returns html from the ajax call or from localStorage.
function render (myObjx) {
var results = '';
for (var prop in myObjx) {
results += '<p>data.' + prop + ' = ' + myObjx[prop] + '</p>';
}
var printData = $('body').html(results);
return printData;
};
You can use the below approach. You can change it as per your requirement.
function checkAvailable(){
var test = 'test';
try {
localStorage.setItem(test, test);
localStorage.removeItem(test);
return true;
} catch(e) {
return false;
}
}
// And you call below to check the availablity
if(checkAvailable() === true){
// available
}else{
// unavailable
}
Related
I've got 3 functions, checkusername(username), checkemail(email), checkpassword(password). The API each one checks against has a rate limit and there has to be a delay of 15 milliseconds between each call. I have tried:
setTimeout(checkusername(username), 1500);
setTimeout(checkemail(email), 1500);
setTimeout(checkpassword(password), 1500);
That doesn't work. I've tried various other ways like increasing the delay by 1500 using a variable:
var delay = 1500;
checkusername(username);
if(delay == 1500) {
delay = delay + 1500;
checkemail(email);
}
else if(delay == 3000) {
delay = delay + 1500;
checkpassword(password);
}
console.log('Checks done!');
None of it works, still getting the code 429 (rate limit exceeded) come up in the console as per from HaveIbeenpwned API.
Either an answer using Javascript or jQuery or I could possibly try it in PHP if there is a solution that way?
By the way each function uses jQuery $.ajax({}) call to the API.
EDIT:
function checkusername(username) {
$.ajax({
url: 'https://haveibeenpwned.com/api/v2/breachedaccount/'+username+'?includeUnverified=true',
type: 'GET',
dataType: 'json',
success: function(data) {
var html = '<h4>Your username was found in the following hacked site breaches:</h4>';
for(i=0;i<data.length;i++) {
var breachName = data[i].Title;
var breachDesc = data[i].Description
html += '<h3><span class="label label-danger">'+breachName+'</span></h3>';
html += '<p>'+breachDesc+'</p>';
html += '<br>';
}
$('#results').append(html);
}
});
}
First, here's a helper function that will return a Promise that will resolve in 15 milliseconds.
function delay15 () {
return new Promise(function(resolve) { setTimeout(resolve, 15) })
}
You'd need to write your checkusername, checkemail, & checkpassword functions to return Promises when the request has completed.
Example checkusername function (note the added return statement):
function checkusername(username) {
return $.ajax({
url: 'https://haveibeenpwned.com/api/v2/breachedaccount/'+username+'?includeUnverified=true',
type: 'GET',
dataType: 'json',
success: function(data) {
var html = '<h4>Your username was found in the following hacked site breaches:</h4>';
for(i=0;i<data.length;i++) {
var breachName = data[i].Title;
var breachDesc = data[i].Description
html += '<h3><span class="label label-danger">'+breachName+'</span></h3>';
html += '<p>'+breachDesc+'</p>';
html += '<br>';
}
$('#results').append(html);
}
});
}
Then you'd write code something like this:
checkusername(username)
.then(delay15)
.then(function() { return checkemail(email) })
.then(delay15)
.then(function() { return checkpassword(password) })
Here's the same code in ES2015, which is shorter, though not as well-supported in browsers:
function delay15 () {
return new Promise(resolve => setTimeout(resolve, 15))
}
checkusername(username)
.then(delay15)
.then(() => checkemail(email))
.then(delay15)
.then(() => checkpassword(password))
your setTimeout method is triggering all 3 requests essentially simultaneously, but 1.5 seconds after the setTimeout is invoked. try chaining your requests as promises or callbacks so you're not sending them all at the same time.
EDIT:
here's your example:
function checkUsername(u) {
return new Promise(function(resolve, reject) {
//check username
if (success) {return resolve();}
else {return reject();}
}
}
checkUsername('username').then(function() {checkNextThing()});
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
You probably have this sorted by now but on the off-chance that you do not then perhaps the following mighht be of use ~ seems to finally work OK! Rather than using jQuery ( I don't use it ) or the traditional XMLHttpRequest this relies upon the newer Fetch api which is based around the notion of Promises
<!doctype html>
<html>
<head>
<title>Have I been pwned?</title>
<script>
var flags={
capture:false,
passive:true,
once:false
};
/* Results from each request will be stored here */
var data={};
/* Whether or not to return FULL data as response */
var truncate=false;
/* Whether or not to include unverified results */
var verified=false;
/* A randomly chosen email address & password for testing */
var username='dave#gmail.com';
var email='andy#yahoo.com';
var password='knickers';
/* No idea who dave#gmail.com or andy#yahoo.com is btw */
/* Request configuration */
var config={
'method':'get',
'mode':'cors'
};
/* Error callback function */
var evtError=function(err){
console.info('oops: %s',err.message);
};
/* Time to wait */
const t=1500;
/* Promise to wait specified time */
const wait = ms => new Promise( resolve => setTimeout( resolve, ms ) );
function create( t, a, p ) {
try{
var el = ( typeof( t )=='undefined' || t==null ) ? document.createElement( 'div' ) : document.createElement( t );
for( var x in a ) if( a.hasOwnProperty( x ) && x!=='innerHTML' ) el.setAttribute( x, a[ x ] );
if( a.hasOwnProperty('innerHTML') ) el.innerHTML=a.innerHTML;
if( p!=null ) typeof( p )=='object' ? p.appendChild( el ) : document.getElementById( p ).appendChild( el );
return el;
}catch(err){
console.warn('createNode: %s, %o, %o',t,a,p);
}
}
function process( data ){
if( typeof( data )=='object' ){
/* use the data */
console.info(data)
var div=document.getElementById('results');
var _username=data.username;
var _email=data.email;
var _pwd=data.password;
/* Process username pwnage */
create('h1',{innerHTML:'Username pwnage for: '+username },div );
for( var n in _username ){
if( typeof( _username[ n ] ) =='object' ){
var keys=Object.keys( _username[ n ] );
var values=Object.values( _username[ n ] );
keys.forEach(function(e,i,a){
create(null,{innerHTML:e+': '+values[i]},div);
});
}
}
/* Process email pwnage */
create('h1',{innerHTML:'Email pwnage for: '+email },div );
for( var n in _email ){
if( typeof( _email[ n ] ) =='object' ){
var keys=Object.keys( _email[ n ] );
var values=Object.values( _email[ n ] );
keys.forEach(function(e,i,a){
create(null,{innerHTML:e+': '+values[i]},div);
});
}
}
/* Finally - password pwnage */
create('h1',{innerHTML:'Password pwnage for: '+password },div );
create(null,{innerHTML:_pwd},div);
}
}
function pwned( event ){
var urls={
username:'https://haveibeenpwned.com/api/v2/breachedaccount/'+encodeURIComponent( username )+'?truncateResponse='+truncate+'&includeUnverified='+verified,
email:'https://haveibeenpwned.com/api/v2/breachedaccount/'+encodeURIComponent( email )+'?truncateResponse='+truncate+'&includeUnverified='+verified,
password:'https://haveibeenpwned.com/api/v2/pwnedpassword/'
};
/* Get the first url using "fetch" rather than XMLHttpRequest */
fetch( urls.username, config ).then( function( res ){
if( res.ok ) return res.json();
if( res.status==404 )return 404;
throw new Error('Failed to check username');
}).then( function( json ){
/* Add the response data to output object */
data.username=json;
}).then( function(){
/* wait for pre-determined time */
return wait( t );
}).then( function(){
/* Get the second url */
fetch( urls.email, config ).then(function( res ){
if( res.ok ) return res.json();
if( res.status==404 )return 404;
throw new Error('Failed to check email');
}).then( function( json ){
/* Add new response data to output object */
data.email=json;
}).then( function(){
/* Loiter, with intent, for a while... twiddle the thumbs etc */
return wait( t );
}).then( function(){
/* Finally get the last url - using POST as I found I was having issues with GET for some reason */
var headers=new Headers();
headers.append('Content-Type','application/x-www-form-urlencoded; charset=UTF-8')
var config={
'mode':'cors',
'method':'post',
'body':'Password='+encodeURIComponent( password ),
'headers':headers
};
fetch( urls.password, config ).then( function( res ){
if( res.ok ) return res.json();
if( res.status==404 )return 404;
throw new Error('Failed to check password');
}).then( function(status){
/* And store the response */
data.password=status==200 ? 'pwned' : 'ok';
return status;
}).then(function(status){
return data;
}).then( function( data ){
/* play with the data */
process.call( this, data );
}).catch( evtError );
}).catch( evtError );
}).catch( evtError );
}
document.addEventListener('DOMContentLoaded',function(){
var bttn=document.querySelector('input[type="button"][name="pwnage"]');
bttn.onclick=pwned;
},flags);
</script>
</head>
<body>
<form method='post'>
<input type='button' name='pwnage' value='Check pwnage' />
<div id='results'></div>
</form>
</body>
</html>
I found that it was possible to lower the timeout period to 1000ms on occasion but seemed a little flaky. The implementation of the method chaining could probably be improved upon but it was my first attempt at a really complicated usage of fetch
Doing further testing lead me to try some of my own email addresses as I'd not been on have I been pwned for quite a while - not a happy bunny after finding a couple had been pwned :(
After calling this $http request (with server.refresh();)
MinecraftServer.prototype.refresh = function(){
return $http.get("http://mcping.net/api/" + this.ip).then(this.acceptData);
}
This function's this is the window object, instead of the MinecraftServer object:
MinecraftServer.prototype.acceptData = function(data){
data = data.data
if(data && data.online){
this.online = data.online;
//do more stuff
} else { // do more stuff }
}
So instead of the MinecraftServer object getting it's attributes updated, the window gets the attributes.
In case this will help, here is my abriged factory code:
.factory('MinecraftServer',function($http){
function MinecraftServer(name, ip) { //does stuff }
MinecraftServer.prototype.acceptData = function(data){
data = data.data
if(data && data.online){
this.online = data.online;
//do more stuff
} else { // do more stuff }
}
MinecraftServer.prototype.refresh = function(){return $http.get("http://mcping.net/api/" + this.ip).then(this.acceptData);}
MinecraftServer.build = function(name, ip){return new MinecraftServer(name, ip)};
return MinecraftServer;
})
this as a callback is using some other this.
Use .bind:
return $http.get("http://mcping.net/api/" + this.ip).then(this.acceptData.bind(this));
I have a function, which will either return a cached template or if the template has not been cached - it will load it via AJAX and then return it. Here's what I've got:
var getTpl = function( name ) {
var cached = cache.get( 'templates' ) || {};
if( cached.hasOwnProperty( name ) ) {
console.log( 'template ' + name + '.mustache found in cache' );
return cached[ name ];
}
else {
console.log( 'requesting ' + name + '.mustache template via AJAX' );
var tpl;
$.ajax( {
url: path.templates + '/' + name + '.mustache',
async: false,
success: function( data ) {
tpl = data;
var cached = store.get( 'miniTemplates' ) || {};
var newTemplate = {};
newTemplate[ name ] = data;
if( ! cached.hasOwnProperty( name ) ) cache.set( 'templates', _.extend( cached, newTemplate ) )
},
error: function() { tpl = false; }
} );
return tpl;
}
}
This works fine. However, Chrome is complaining about:
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check http://xhr.spec.whatwg.org/.
Therefore I wanted to switch to using $.deferred, but I can't wrap my head around it. How can I re-write the function above, so calling getTpl would always return a template (either form the cache or directly from the AJAX request)?
You can use promise/deferred concept to achieve your needs
var getTpl = function( name ) {
var promise;
var cached = cache.get( 'templates' ) || {};
if( cached.hasOwnProperty( name ) ) {
console.log( 'template ' + name + '.mustache found in cache' );
var df = new $.Deferred();
df.resolve(cached[ name ]);
promise = df.promise();
} else {
console.log( 'requesting ' + name + '.mustache template via AJAX' );
promise = $.ajax({
url: path.templates + '/' + name + '.mustache'
}).then(function(data) {
tpl = data;
var cached = store.get( 'miniTemplates' ) || {};
var newTemplate = {};
newTemplate[ name ] = data;
if( ! cached.hasOwnProperty( name ) ) cache.set( 'templates', _.extend( cached, newTemplate ) )
return tpl;
});
}
return promise;
}
Then, call your method like this:
getTpl('xyz')
.then(function(template) {
// you have the template, either from cache or fetched via ajax
})
.fail(function(err) {
console.log(err);
});
Since you appear to appear to already be using underscore/lodash, you can make use of memoization rather than maintaining your own cache.
The beauty of promises is that you can access them again and again and they will always produce the same value:
var getTpl = _.memoize(function( name ) {
console.log( 'requesting ' + name + '.mustache template via AJAX' );
return $.ajax({
url: path.templates + '/' + name + '.mustache'
});
});
Yes, it really is that simple.
Then you can just use it like any other promise:
getTpl('myTemplate').then(function (template) {
// use template
}, function (error) {
console.log('Could not retrieve template.', error);
});
I am using the nodejs request module from here: https://github.com/mikeal/request -- There are cookies involved but not part of this code.
Excuse the non-optimized code, I've been trying various stuff trying to fix this problem with no success. I have this simple script:
function getPage(curpage)
{
if(curpage <= pages)
{
var newpage = curpage + 1;
console.log('getting page '+newpage );
request.get({ uri: 'http://someurl.com/test', qs: { p : newpage }}, function(error, response, body) {
if(error)
{
[...]
}
else
{
console.log(response.req.path);
}
getPage(newpage);
});
}
else
{
console.log("We're done!\n");
process.exit();
}
}
The problem here, is my response.req.path seems to get stuck at 2. I get:
getting page 1
/id/bradpitt5/inventoryhistory?p=1
getting page 2
/id/bradpitt5/inventoryhistory?p=2
getting page 3
/id/bradpitt5/inventoryhistory?p=2
getting page 4
/id/bradpitt5/inventoryhistory?p=2
As you can see, the "newpage" is used properly when getting the page, but the request path is set wrong? I can't make sense out of this. Can anyone figure out what I am doing wrong here?
I just start with getPage(0);
I also did this using a different method, just to make sure I wasn't crazy:
for( var i = 1; i <= pages; i++ ) {
urls.push( {'url' : 'http://somepage.com/test?p='+ i, 'done' : false } );
}
function getNextPage() {
for(var i = 0; i < pages; i++ ) {
if( urls[i].done == false ) {
break;
}
}
if( urls[i] && urls[i].done == false ) {
urls[i].done = true;
console.log( 'requesting: '+ urls[ i ].url );
request.get( urls[ i ].url, function(error, response, body) {
if(error) {
[...]
} else {
console.log( 'received: '+ response.req.path +' ok. ');
}
getNextPage();
}
);
} else {
console.log("we're done!");
process.exit();
}
}
This also gets stuck at page 2.
The implication is that:
{ uri: 'http://someurl.com/test', qs: { p : newpage }}
is not being updated each time request.get() is called. I wonder if it is worth trying to create a new variable:
var options = {
uri: 'http://someurl.com/test',
qs: {
p: newpage
}
};
// let's debug just to be sure
console.log( " options = %s", JSON.stringify( options, null, 2 ) );
request.get( options, function(error, response, body) {
...
I don't know if this is the case but I wonder if the object created within the function call isn't evaluated just once.
It appears I only had "2 pages" of data, and the site I was requesting from redirected to the last page if I was trying to go higher than the number of pages. :(
I have this code in my ActionResult
public ActionResult Copy( int bvVariableid ) {
var iReturn = _bvRepository.CopyBenefitVariable( bvVariableid, CurrentHealthPlanId, CurrentControlPlanId, _bvRepository.GetSecInfo( ).UserId, IsNascoUser());
if (iReturn == -999)
return new JavaScriptResult() { Script = "alert(Unique variable name could not be created');" };
if( iReturn != -1 )
return Json( new { RedirectUrl = string.Format( "/BvIndex/Index/{0}?bvIndex-mode=select", iReturn ) } );
return RedirectToRoute( "Error" );
}
This is the code i have in my View.
CopyBenefitVariable = function (bvId, bvName) {
if (confirm('Are you sure you want to copy from the Benefit Variable ' + bvName + ' ?')) {
$.post(
"/BvIndex/Copy/",
{ bvVariableid: bvId },
function (data) {
window.location = data.RedirectUrl;
}, "json");
}
};
When IReturn is -999 I am not getting the JavaScriptResult alert box on my page.
is that something I am doing wrong here?
Can any body help me out.
Thanks
I thing, there is a bug in this line:
return new JavaScriptResult() { Script = "alert(Unique variable name could not be created');" };
Corrected :
return new JavaScriptResult() { Script = "alert('Unique variable name could not be created');" };
Your problem is likely stemming from your client-side JavaScript. The .post() method in ajax is actually a shortcut for:
$.ajax({
type: 'POST',
url: url,
data: data,
success: success,
dataType: dataType
});
So your client-side code is telling jQuery to interpret the result as a json object (even though you sent back a script).
$.post(
"/BvIndex/Copy/", // url
{ bvVariableid: bvId }, // data
function (data) {
window.location = data.RedirectUrl; // success
},
"json" // dataType
);
I would change your code to look like this:
public ActionResult Copy( int bvVariableid ) {
var iReturn = _bvRepository.CopyBenefitVariable( bvVariableid, CurrentHealthPlanId, CurrentControlPlanId, _bvRepository.GetSecInfo( ).UserId, IsNascoUser());
if (iReturn == -999)
return new Json(new { type = "msg", data = "Unique variable name could not be created" });
if( iReturn != -1 )
return Json( new { type = "url", data = string.Format( "/BvIndex/Index/{0}?bvIndex-mode=select", iReturn ) } );
return RedirectToRoute( "Error" );
}
And your view code should look like this:
CopyBenefitVariable = function (bvId, bvName) {
if (confirm('Are you sure you want to copy from the Benefit Variable ' + bvName + ' ?')) {
$.post(
"/BvIndex/Copy/",
{ bvVariableid: bvId },
function (data) {
if (data.type == "url") {
window.location = data.RedirectUrl;
} else if (data.type == "msg") {
alert(data.data);
}
}, "json");
}
};
You can mark down my answer if you like, but it is generally accepted that the JavaScriptResult was a bad move on the ASP.NET MVC team's part. That being said, your sample already returns a Json Action Result for one of your conditions. You could do the same for both items. If you altered your JSON object like:
return Json( new { success = bool, RedirectUrl = value } );
Then you could change your client function to something like:
function (data) {
if(data.success === true) {
window.location = data.RedirectUrl;
} else {
alert('Unique variable name could not be created');
}
}
I know it doesn't directly address the issue with JavaScriptResult, but it should get the intended result of the code.