Bug with AngularJS and Chrome, pending sockets after canceling? - google-chrome

Has anyone seen this bug with AngularJS (v1.0.7) and Chrome (Version 30.0.1599.114) where canceling http GET request puts the sockets into a pending state thus maxing out the thread pool in chrome?
Code:
if ($scope.canceler !== undefined) {
$scope.canceler.resolve();
$scope.canceler = undefined;
}
$scope.canceler = $q.defer();
$http.get("/apicall", {
cache: myCache,
timeout: $scope.canceler.promise
}).success(function (results) {
}).
error(function (result) {
});
Might be the same bug 241844

You should update AngularJS to 1.1.5 to be able to cancel http calls.
ref: In AngularJS, how to stop ongoing $http calls on query change
Here is the working code and the JS fiddle. I have tested with AngularJS 1.2.0 and Chrome 32.0.1700.0 canary.
function Ctrl($rootScope, $scope, $http, $q, $timeout) {
var canceler = $q.defer();
console.log("Calling...");
$http.get("/echo/json", {
//Will return data after 5 seconds passed
data: {json: {id: "123"}, delay: 5},
timeout: canceler.promise
}).success(function (results) {
console.log("Success");
console.log(results);
}).
error(function (result) {
console.log("Error");
console.log(result);
});
$timeout(function () {
console.log("1 second passed");
// now, cancel it (before it may come back with data)
$rootScope.$apply(function () {
console.log("Canceling..");
canceler.resolve();
});
}, 1000);
}
http://jsfiddle.net/7Ma7E/4/
The request was become cancelled state.

Related

Why is my Response of Type Vague on this google cloud function?

I am calling a Google Cloud Function. I have a green arrow beside the function. I have enabled it to use HTTP. I have enabled it to work without authorization.
When I call it I get an error 403 and an object that says response type opaque. I have no idea what is wrong now ...
I have spent an entire day on this. And I'm so confused.
I'm calling it from both localhost:3000, and from an app I built on https://djit.su/
I have tried my best to figure out the CORS and everything else, but I am so stuck.
At this point I just want it to return "hey" to my local machine...
Here is my Google Cloud FN:
'use strict'
const functions = require('firebase-functions');
const cors = require('cors')({
origin: true,
});
exports.date = functions.https.onRequest((req, res) => {
console.log('Made it to here!');
if (req.method === 'PUT') {
return res.status(403).send('Forbidden!');
}
return cors(req, res, () => {
const stringVar = 'This is a string var';
console.log('Hi from inside cloud fn');
console.log('Sending:', { name: "Hi I'm Rick", stringVavr: stringVar });
const options = {
secure: false,
signed: false,
sameSite: None,
};
res.cookie('session', 'ABCE', options);
res.set('Access-Control-Allow-Methods', 'GET');
res.set('Access-Control-Allow-Headers', 'Content-Type');
res.set('Access-Control-Max-Age', '3600');
res.header('Access-Control-Allow-Origin', '*');
res.set('Access-Control-Allow-Origin', '*');
if (req.method === 'OPTIONS') {
res.set('Access-Control-Allow-Methods', 'GET');
res.set('Access-Control-Allow-Headers', 'Content-Type');
res.set('Access-Control-Max-Age', '3600');
res.status(204).send('');
}
});
});
Here is my React code:
async function getNum() {
await fetch(
'https://us-central1-provable-fair-algo-rick.cloudfunctions.net/randomHash',
{ mode: 'no-cors' }
)
.then(function (response) {
// return response.text();
console.log(response);
console.log(json.response);
Promise.resolve(response);
console.log(Promise.resolve(response));
})
.then(function (text) {
console.log('Request successful', text);
})
.catch(function (error) {
console.log('Request failed', error);
});
Here is the console.log
Response {type: "opaque", url: "", redirected: false, status: 0, ok: false, …}
body: (...)
bodyUsed: false
headers: Headers {}
ok: false
redirected: false
status: 0
statusText: ""
type: "opaque"
url: ""
The issue seems to be on your react code, as you are using { mode: 'no-cors' } however the Cloud Function is using CORS as it is in a different domain.
Here it explains that using no-cors can generate this opaque response:
no-cors is intended to make requests to other origins that do not have CORS headers and result in an opaque response, but as stated, this isn't possible in the window global scope at the moment.
A way to correct this would be to use: { mode: 'cors' } The code will be as the following:
function getNum() {
await fetch(
'https://us-central1-provable-fair-algo-rick.cloudfunctions.net/randomHash',
{ mode: 'cors' }
)
.then(function (response) {
// return response.text();
console.log(response);
console.log(json.response);
Promise.resolve(response);
console.log(Promise.resolve(response));
})
.then(function (text) {
console.log('Request successful', text);
})
.catch(function (error) {
console.log('Request failed', error);
});

Puppeteer Google Cloud Function Pub/Sub Trigger can't open browser

I'm trying to create a Puppeteer function in GCP which can be triggered by Pub/Sub messages. The function is callable, but doesn't behave as expected and throws a Timeout Error once browser tries to initialize. Could the trigger possibly be using a NodeJS environment different from HTTP trigger?
I'm also very new to NodeJS, so I apologize ahead of time if the issue is blatantly obvious.
I've created an HTTP trigger for the function which behaves as expected. I copy/paste the Puppeteer Function below into the index.js when creating the Cloud Function, but separated in example for clarity that both triggers are running the identical function.
Puppeteer Function
const puppeteer = require('puppeteer');
scrapeUglyWebsite = () => {
return new Promise(async(resolve, reject) => {
await puppeteer.launch({
headless: true,
args: ['--no-sandbox']
})
.then(async (browser) => {
const page = await browser.newPage();
await page.goto('http://suzannecollinsbooks.com/', {waitUntil: 'load', timeout: 0})
.then(async () => {
//Wait for content to load
await page.waitForFunction('document.body !== null && document.body.innerText.includes(\'Jon Scieszka\')');
//Evaluate page contents
const dom_eval = await page.evaluate(() => document.body.innerText.includes("Here’s a picture of me with a rat"));
await browser.close();
resolve(dom_eval);
});
}).catch((err) => {
reject(err);
});
});
};
HTTP Trigger - index.js
exports.cloudFunctionTest = (req, res) => {
scrapeUglyWebsite()
.then((results) => {
if(results) {
res.send('Suzanne Collins takes pictures with rats.');
} else {
res.send("Suzzane Collins doesn't take pictures with rats.");
};
})
.catch((err) => {
res.send(err.toString());
});
Pub/Sub Trgger - index.js
exports.cloudFunctionTest = (data, context) => {
scrapeUglyWebsite()
.then((results) => {
if(results) {
console.log('Suzanne Collins takes pictures with rats.');
} else {
console.log("Suzzane Collins doesn't take pictures with rats.");
};
})
.catch((err) => {
console.log(err.toString());
});
};
package.json
{
"name": "test",
"version": "0.0.1",
"engines": {
"node": "8"
},
"dependencies": {
"puppeteer": "^1.6.0"
}
}
HTTP Trigger behaves correctly with the expected result
Suzanne Collins takes pictures with rats.
Pub/Sub Trigger throws the following error with no output
TimeoutError: Timed out after 30000 ms while trying to connect to Chrome! The only Chrome revision guaranteed to work is r662092
I know this is late but the reason that the TimeoutError occurs is because cloud functions do not automatically wait for async tasks to finish completing. So in exports.cloudFunctionTest, scrapeUglyWebsite() is called but the function does not wait for the promise to be fulfilled, so the program terminates. Hence the error
More info here on how background functions work in NodeJs
In order for the function to wait for scrapeUglyWebsite(), you need to return a promise that completes when scrapeUglyWebsite() and the resulting code is complete.
Personally, I got it to work by simply wrapping the code currently in the function I am exporting in another async function and then returning the promise of the wrapper function.
async function wrapper() {
try {
const result = await scrapeUglyWebsite();
if(results) {
console.log('Suzanne Collins takes pictures with rats.');
} else {
console.log("Suzzane Collins doesn't take pictures with rats.");
};
} catch (err) {
console.log(err.toString());
}
}
Then in the function you want to export:
exports.cloudFunctionTest = (data, context) => {
return wrapper();
};

prevent AJAX success result to download file or open

I have this jquery to make a post request:
$('#btnAdd').click(function (e) {
$('#modal_processing').modal('show');
$('#modal_body_process').html("Please wait while we are processing your request. This message will automatically close when request successfully completed.");
$('#modal_title_process').html("Processing...");
$.ajax({
url: '#Url.Action("AddNew", "Home")',
type: 'POST',
data: {
Name: $('#txtEmail').val(),
Project: $('#cbProject').val(),
Gender: $('#cbGender').val(),
Level: $('#cbLevel').val(),
ShiftStart: $('#txtShiftStart').val(),
ShiftEnd: $('#txtShiftEnd').val(),
GeoId: $('#cbGeo').val(),
TowerId: $('#cbTower').val(),
ProcessId: $('#cbProcess').val(),
PrimaryTeamId: $('#cbPrimaryTeam').val(),
RegionId: $('#cbRegion').val(),
WBSId: $('#cbWBS').val(),
},
dataType: "json",
success: function (response) {
$('#modal_body_process').html("New user has been successfuly added.");
$('#modal_title_process').html("Successful!");
setTimeout(function () {
$('#modal_processing').modal('hide');
}, 3000);
},
error: function (resp) {
$('#modal_body_process').html("Please fill out all required fields.");
$('#modal_title_process').html("Error");
setTimeout(function () {
$('#modal_processing').modal('hide');
}, 3000);
alert("Error");
}
});
});
in my controller, i have this:
if (result.IsSuccessStatusCode)
{
ModelState.Clear();
return Json(result.StatusCode, JsonRequestBehavior.AllowGet);
}
return View(model);
my problem is, everytime the result is success, it always prompting me to download the json file (IE 11) and for mozilla, it opens the json file.
how can i prevent this?

AngularJS - store page data

I would like to store my datas with local storage or cookie. The data source is a json and this json has a data limitation (10 data per page). So I implemented a "show more" function, which is loads the other jsons when I click a button.
My problem is that I can't store properly the whole loaded datas. I tried with different techniques, but nothing.
Here is the html:
<div ng-controller="MyCtrl">
<div ng-repeat="item in items">
<p>{{item.title}}</p>
</div>
<button ng-click="getItems()" ng-hide="items.length == 0">show more</button>
</div>
And here is the controller:
app.controller('MyCtrl', function($scope, $http) {
$scope.items = [];
var page = 1;
$scope.getItems = function () {
var url = 'https://differentdomain.com/json&page=' + page++;
$http({method: 'GET', url: url}).
success(function (data, status, headers, config) {
if (status == 200) {
$scope.items = $scope.items.concat(data.results);
// or other way
// $scope.items.push.apply($scope.items, data.results)
} else {
console.error('Error happened while getting list.')
}
}).
error(function (data, status, headers, config) {
console.error('Error happened while getting the list.')
});
};
$scope.getItems();
});
Anybody has idea, how can I store it the loaded datas?
If all you want to know is hot to store data you can just use localStorage.setItem to save data and localStorage.getItem to retrieve those data.
The simplest implementation would be
app.controller('MyCtrl', function($scope, $http) {
//retrieving saved object or init new array
$scope.getItems = function () {
//XXX if page is last one then return;
//current page is basically num of objects divided by page size (10 in this case)
var page = ($scope.items.length / 10) + 1;
var url = 'https://differentdomain.com/json&page=' + page++;
$http({method: 'GET', url: url}).
success(function (data, status, headers, config) {
if (status == 200) {
$scope.items = $scope.items.concat(data.results);
//saving current object
localStorage.setItem('items', JSON.stringify($scope.items));
} else {
console.error('Error happened while getting list.')
}
}).
error(function (data, status, headers, config) {
console.error('Error happened while getting the list.')
});
};
$scope.items = JSON.parse(localStorage.getItem('items')) || [];
if (!$scope.items.length) $scope.getItems();
});
The above should work, I assume it is loading 10 more each time you click the button.
Your question seems to be how can you persist those loaded items between browser sessions. If so my suggestion would be for you to look at:
https://github.com/goodeggs/angular-cached-resource
This abstracts away all the difficult parts such as persistence and cache retrieval to give you a consistent API.

AngularJS 1.2.7 IE8 resource bug

Sample code available here & here. Since Plunker doesn't support IE8 or IE9 very well, the example code can be run by opening the Plunker example in a modern web browser and then launching the Run pane in a separate window and opening that URL in IE8 or IE9.
When making a RESTful call using $resource.query or $resource.get, the promise fails to return any results on IE8 or IE9 if a custom action is defined and used:
factory('ResourceService2', ['$resource', '$q', function($resource, $q) {
var factory = {
query: function() {
var deferred = $q.defer();
$resource('data.json', {'cacheSlayer' : new Date().getTime()}, {
'query': {
method: 'GET',
responseType: 'json',
isArray: true
}}).query(function (data) {
deferred.resolve(data);
});
return deferred.promise;
}
};
return factory;
}]).
query():
ResourceService2.query().then(function (response) {
$scope.resource2Rows = response;
});
However, this same call successfully returns results when a custom action is not defined or used:
factory('ResourceService', ['$resource', '$q', function($resource, $q) {
var factory = {
query: function() {
var deferred = $q.defer();
$resource('data.json', {
'cacheSlayer' : new Date().getTime()
}, {}).query(function (data) {
deferred.resolve(data);
});
return deferred.promise;
}
};
return factory;
}]).
query():
ResourceService.query().then(function (response) {
$scope.resourceRows = response;
});
Using $http is also successful:
factory('HttpService', ['$http', '$q', function($http, $q) {
var factory = {
query: function() {
var deferred = $q.defer();
$http.get('data.json', {
params: {
'cacheSlayer' : new Date().getTime()
}}).success(function (data) {
deferred.resolve(data);
});
return deferred.promise;
}
};
return factory;
}]).
get():
HttpService.query().then(function (response) {
$scope.httpRows = response;
});
Is this a bug in IE8/IE9? What additional parameters for a custom action must be defined for IE8/IE9 compatibility? The Angular Developer's Guide makes no mention of this problem as of 1.2.7.
CORS is not implemented fully in ie8/9 so this is most likely your issue. Here is the msdn article about it:
http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx