I have this code which sends a string into chuncks.
Everything is OK expect that when the script is posting to the server #status doesn't update.
The request is sync and not async because I want to post one chunk at a time and not everything at onces.
for (var packet in packets) {
var calculated = ((packet/(packets_lenght-1))*100);
$('#status').text(calculated);
var formData = new FormData();
formData.append("packet", packets[packet]);
formData.append("packet_num", packet);
formData.append("name", 'name');
var request = new XMLHttpRequest();
request.open("POST", "index.php", false);
request.send(formData);
}
Can someone tell me what I am doing wrong?
Thanks.
That is because browser didn't refresh view state while he is busy by execution code ( js executed in single threat - so in case of sync requests - ints normal )
you should async iterations over array like this http://jsfiddle.net/7TzF8/
Sorry - z made minor changes to just show idea, you can refactor your code according main idea
var packets = str2chunk(JSON.stringify(frames_array).split('data:image/jpeg;base64,').join(''), 10);
var packets_lenght = packets.length;
function processPacket(packet){
if(packet >= packets_lenght){
return;
}
$.ajax({
type: "POST",
url: "http://fiddle.jshell.net/echo/jsonp/",
data: {
packet: packets[packet],
packet_num: packet,
name: 'name'
},
success: function (answer) {
console.log(packet);
var calculated = ((packet / (packets_lenght - 1)) * 100);
$('#status').text(calculated + '%');
processPacket(packet+1);
},
error: function () {
}
});
}
processPacket(0);
Related
Before I explain what I want to do, here's an MCV of what I'm coding
$("#button").submit(function(event) {
event.preventDefault();
var formData = new FormData(this);
var myString = $('#textarea').val();
var myRegexp = /src="blob:([^'"]+)"/gm;
match = myRegexp.exec(myString);
var inProgress = 0;
while (match != null) {
var xhr = new XMLHttpRequest();
addr = match[1];
xhr.open('GET', 'blob:' + addr, true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var myBlob = this.response;
var data = new FormData();
data.append('file', myBlob);
$.ajax({
url: "uploader.php",
type: 'POST',
data: data,
contentType: false,
processData: false,
beforeSend: function() {
inProgress++;
},
success: function(data) {
myString = myString.replace("blob:" + addr, data);
},
error: function() {
// error
},
complete: function() {
--inProgress;
}
});
} else {
// error
}
};
xhr.send();
match = myRegexp.exec(myString);
}
if (!inProgress) {
formData.set('textarea', myString);
submitForm(formData);
}
});
So, I have a text area and it contains an unknown number of BLOB objects. I first try to find these BLOB objects using regexp and then I upload them to the server using a PHP file called uploader.php. Once the file is uploaded, it will return the URL of the uploaded file and I want to replace the BLOB URL by the URL of the uploaded file in the text area and then submit the final content of the textarea to the server for further processing.
It turns out that when I run the code, only the last instance of the regexp is replaced by its uploaded URL. The others remain as they were. I suspect that this is because the while loop does not wait for the ajax requests to be complete. I had a similar problem when trying to submit the form and I solved it by following the suggestions in this answer but I don't know how to fix this issue this time.
Any idea is appreciated
Update: I tried to make ajax work synchronously but my browser said that it was deprecated and it didn't work.
It seems you don't really need it to be synchronous (and I can't see a case when it's better to make an async action look synchronous), but rather only need it to be sequential.
It is possible to make async actions sequential by the use of callbacks (which are rewritable as Promise and in turn rewritable as async/await methods but I'll keep it simple):
// myString is made global for simplicity
var myString;
function uploadBlob(myBlob, addr, callback) {
var data = new FormData();
data.append('file', myBlob);
$.ajax({
url: "uploader.php",
type: 'POST',
data: data,
contentType: false,
processData: false,
success: function(data) {
// file uploaded OK, replace the blob expr by the uploaded file url(data)
myString = myString.replace("blob:" + addr, data);
callback();
},
error: function() {
// error, the uploaded most likely failed, we leave myString alone
// or alternatively replace the blob expr by empty string
// because maybe we dont want to post blob in the final form submit
// uncomment if needed
// myString = myString.replace("blob:" + addr, "");
callback();
}
});
}
function getBlobAndUpload(addr, callback) {
var xhr = new XMLHttpRequest();
xhr.open('GET', 'blob:' + addr, true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var myBlob = this.response;
uploadBlob(myBlob, addr, callback);
} else {
// error, but callback anyway to continue processing
callback();
}
};
xhr.send();
}
function processAddresses(addresses, callback, current) {
var index = current || 0;
// all addresses processed?
if (index >= addresses.length) {
// yes no more address, call the callback function
callback();
} else {
var addr = addresses[index];
// once the get/upload is done the next address will be processed
getBlobAndUpload(addr, function() {
processAddresses(addresses, callback, index + 1);
});
}
}
$("#button").submit(function(event) {
event.preventDefault();
var formData = new FormData(this);
var addresses = [];
// initialize both localString and myString to the content of the textArea
// localString will be used to extract addresses,
// while myString will be mutated during the upload process
var localString = myString = $('#textarea').val();
var myRegexp = /src="blob:([^'"]+)"/gm;
match = myRegexp.exec(localString);
// collect all addresses first
while (match != null) {
addr = match[1];
addresses.push(addr);
match = myRegexp.exec(localString);
}
// initiate sequential processing of all addresses, and
// pass the callback function triggering the form submit
processAddresses(addresses, function() {
// all the successfully uploaded blob exprs in my string should
// be now replaced by the remote file url now (see commented part
// in upload blob error for a variation of the feature
formData.set('textarea', myString);
submitForm(formData);
});
});
So. I said in comments, that you could use async/await, and gave links. Now I am going to try to teach you how to work with promises and XMLHttpRequest.
So first thing. I would use my own 'library' (not really a library, just 3 new command) called PromiseReq which has XMLHttpsRequest that returns Promises.
You would need two functions from it:
sendToServer(config, data) and getServerFile(config). They do what their names implies.(sendToServer is not so good at the time, but I will improve it sometime later). They just use Promises as returns. They work in very easy way. Code # Github
BUT It was designed for my uses only, so it is not very flexible (although I hope I will improve it sometime).
So we need to learn how to use Promises.
Firstly you need to know what Promise is and why do we use it.
Then you can create one like this:
let pmq = new Promise((res,rej)=>{
// PROMISE BODY HERE
});
Here first warning. Promises made that way don't support return as a way to resolve Promise! You have to use res()!
Some functions just return them (such as fetch()) and we can handle them right after calling function.
Now pmq will be our promise.
You can use pmq.then(callback) to handle what will happen if somewhere in promise body is res() call and pmq.catch(callback) to handle what happens when rej() is called. Remember, that .catch(cb) and .then(cb) returns a Promise, so you can safely chain more than one .then() and at the end add .catch() and it will handle rejection from every one of .then()s.
For example:
pmq = fetch("file.txt");
pmq.then(e=>console.log(e.json())).then(console.log).catch(console.error);
There is a big note there.
The order in which this events will fire.
If for example rP() waits 1s than logs "A" then resolves, this code:
let a = rP();
a.then(_=>console.log("B")).catch(console.error);
console.log("C");
will result in:
C
A
B
Becuase of this there is async/await needed to do this.
To do so you have to make an async function with keyword async.
let fn = async ()=>{}
Here is second thing. Async functions ALWAYS return Promise. And that is the second way you can create a promise. You just don't use res(), rej() only return and throw.
Now we can call inside fn():
let a = await rP().then(_=>console.log("B")).catch(console.error);
console.log("C");
and we will get our
A
B
C
Now. How to use it with XMLHttpRequest?
You need to create new Promise with simple XMLHttpRequest inside:
let xmlp = (type, path,data) => return new Promise((res,req)=>{
let xhr = new XMLHttpsRequest();
xhr.open(type, path, true); // true implies that is it asynchronous call
//...
xhr.send(data);
});
And now when to resolve?
XMLHttpRequest has useful event properties and events. The one that is best for our case is onreadystatechange.
You can use it like so:
xhr.onreadystatechange = _=>{
if(xhr.readyState === 4 && xhr.status === 200) // Everything went smoothly
res(xhr.responseText);
else if(shr.readyState === 4 && xhr.status !== 200) // Something went wrong!
rej(xhr.status);
}
And then to get data you can either
Async/Await
// INSIDE ASYNC FUNCTION
let resData = await xmpl("GET", "path.txt", null).catch(console.error);
.then()
let resData;
xmpl("GET", "path.txt", null).then(r=>{
resData = r;
// REST OF WHOLE FUNCTION TO ENSURE THAT resData HAS BEEN SET
})
.catch(console.error);
You can also send data with xmpl().
xmpl("POST", "observer.php", "Data to send to observer.php!")
.then(whatToDoAfterSendFN);
/*
to get such data in PHP you have to use
$post = file_get_contents('php://input');
*/
I know that this answer is a bit messy and stuff, but I didn't have any idea how to write it :P Sorry.
I'm attempting to make a call to an API, which takes requests in the form of Mongodb's '.find' method.
Using postman I can make the following call and I get the correct response.
http://asterank.com/api/asterank?query={"full_name": {"$eq" : "(2004 EU22)"}}&limit=5
But, when I try to make the same call in JavaScript, my entire web application just shows a blank webpage. So is the following way of utilizing a mongodb call wrong?
var example = "0";
function getAsterank(){
//ARRAY OF NEO NAMES
var xhr = new XMLHttpRequest();
xhr.open("GET", 'http://asterank.com/api/asterank?query={"full_name": {"$eq" : "(2004 EU22)"}}&limit=5', false);
xhr.send(null)
responseData = JSON.parse(xhr.response);
xhr.abort();
example = responseData;
}
If I make this same exact JS call using a different api such as the following, it works just fine. I use sublime text so I don't think I can debug it to see whats actually happening.
v
ar MeMe = "0";
function getAsterank(){
//ARRAY OF NEO NAMES
var xhr = new XMLHttpRequest();
xhr.open("GET", 'https://api.nasa.gov/neo/rest/v1/feed/today?detailed=true&api_key=NnRe38qGPTpKPtsenpkqROMTtXvkWnVNyql9lmnP', false);
xhr.send(null)
responseData = JSON.parse(xhr.response);
xhr.abort();
MeMe = responseData;
}
if jquery is an option this might be a solution
$(document).ready(function(){
$(".submitBottom").click( function() {
$.ajax({
type: "GET",
url: 'http://asterank.com/api/asterank?query={"full_name":{"$eq":"(2004 EU22)"}}&limit=5',
encode: true,
success: function (data) {
console.log("success", data)
}
});
});
});
I'm building a tracking library to send events to the backend. An event should be created every 5 seconds (configurable) and sent into the tracking queue, and the tracking queue should be sent to the backend and emptied every 5 seconds (also configurable). The expected behaviour is that an event should be sent to the backend every 5 seconds.
When I was just console.logging the events, everything was working as expected, but when I implemented the xhr request, the interval events were only created every 9 seconds or so. So an event would be sent to the backend, only once every two times the 'post' function fired.
sendData: function(){
var toSend = [].concat(Tracking.__tracking_queue);
if(toSend.length !== 0){
var sendData = this.__stringifyAndSetHeaders(toSend);
Tracking.postData(sendData);
}
},
postData: function(sendData){
var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log(xhr.responseText);
Tracking.__tracking_queue = [];
};
xhr.open("POST", sendData.url, true);
Object.keys(sendData.headers).forEach(function(key){
xhr.setRequestHeader([key], sendData.headers[key]);
});
xhr.send(sendData.body);
}
The backend is receiving the data, but not at the correct times. sendData is being called from within a setInterval loop.
setInterval(function(){
self.sendData()
}, 5000);
I had the same setup working perfectly before, in another file using axios, but I cannot use axios in this use-case.
You are resetting the tracking data at the wrong location. You read the data, than make a request, after the request is done, you delete the data. There is a period of time where data can come into the queue between the request and when it finishes.
sendData: function(){
var toSend = [].concat(Tracking.__tracking_queue);
if(toSend.length !== 0){
var sendData = this.__stringifyAndSetHeaders(toSend);
Tracking.__tracking_queue = []; //clear it here
Tracking.postData(sendData);
}
},
postData: function(sendData){
var xhr = new XMLHttpRequest();
xhr.onload = function() {
console.log(xhr.responseText);
//Tracking.__tracking_queue = []; //don't clear it here
};
xhr.open("POST", sendData.url, true);
Object.keys(sendData.headers).forEach(function(key){
xhr.setRequestHeader([key], sendData.headers[key]);
});
xhr.send(sendData.body);
}
The problem:
I'm uploading images via JavaScript to a asp.net server page. To compute the progressive operation for each image uploading, I designed that each image has an independent request. But I'm afraid this may overload the server, specially if the number of requests is big.
The idea:
Rather than sending all requests asynchronously I want to send them as packets of three.
After those three are sent and all other requests have to wait until those three finished.
The Question:
How i can make the the other requests to wait until the previous ones
finish?
The code:
for (var i = 0; i < inputFiles.files.length; i++) {
(function (i) {
var request = new XMLHttpRequest();
request.open('POST', 'Ajax.ashx');
request.setRequestHeader('Cashe-Control', 'no-cashe');
var data = new FormData();
data.append('file[]', inputFiles.files[i]);
request.upload.addEventListener('progress', function (event) {//happening
if (event.lengthComputable) {
var percent = parseFloat(event.loaded) / parseFloat(event.total),
progressWidth = percent * parseFloat(progressBarWidth);
progressBar.children().css('width', progressWidth + 'px');
} else {}
});
request.upload.addEventListener('load', function (event) {});
request.upload.addEventListener('error', function (event) {});
request.addEventListener('readystatechange', function (event) {
if (this.readyState == 4) {
if (this.status == 200) {
var code = eval(this.response);
} else {}
}
});
request.send(data);
})(i);
}
Because you've added the jQuery tag, you could:
create n $.ajax() requests
wait with the help of $.when() until all of them resolved
and then send the next n requests
Something like this:
function uploadImages(images) {
var requests = [];
// upload 3 images (or less, if there are less images in the array)
for (var i = 0, len = Math.min(3, images.length); i < len; i++) {
var image = images.pop(),
formData = new FormData(),
request, formData = new FormData();
formData.append('file[]', image);
request = $.ajax({
url: "Ajax.ashx",
type: "POST",
data: formData,
processData: false,
beforeSend: function (xhr) {
// add progress stuff
// http://www.dave-bond.com/blog/2010/01/JQuery-ajax-progress-HMTL5/
},
success: function (data) { }
});
requests.push(request);
}
// when all our requests have finished and there are images left, start the next round...
$.when.apply($, requests).done(function () {
if (images.length) {
uploadImages(images);
}
});
}
Simplified Example
The solution:
i was using jquery 1.4 version so it did not work.
Now i'm working on 1.11 version and all done well.
$.when.apply() just work with jQuery 1.5 or later.
I have two projects; first one is a asp.net web project and the second one is embedded http server library project.
Embedded http server project is taken from : embedded http server project
I want to save a video file from user's local to user's shared storage. I'm getting and sending file from browser using ajax request. Embedded http server is supposed to get byte array and save video on client's shared storage. I have a problem that I spent days to solve but not yet found a solution.
In Chrome it stuck on stream.CopyTo(streamReader);.
In Firefox and IE it gives "Cross-Origin Request Blocked" error but Firefox saves file even it gives the error.
Here is the ajax request code:
$(document).ready(function () {
function hashFile(file, chunkSize, callback) {
var size = file.size;
var offset = 0;
var chunk = file.slice(offset, offset + chunkSize);
SendChunk(chunk,0);
var hashChunk = function () {
var reader = new FileReader();
reader.onload = function (e) {
offset += chunkSize;
if (offset < size) {
chunk = file.slice(offset, offset + chunkSize);
SendChunk(chunk,0);
}
else if (offset > size){
offset -= chunkSize;
var newchunkSize = size - offset;
chunk = file.slice(offset, offset + newchunkSize);
SendChunk(chunk,1);
}
};
reader.readAsArrayBuffer(chunk);
};
function SendChunk(chunk,end){
if(end>0)
{
var ajaxRequest = $.ajax({
type: "POST",
url: "http://clientip:8080/savefileend",
contentType: false,
processData: false,
data: chunk
});
}
else{
var ajaxRequest = $.ajax({
type: "POST",
url: "http://clientip:8080/savefile",
contentType: false,
processData: false,
data: chunk
});
ajaxRequest.done(function (e) {
hashChunk();
});
ajaxRequest.error(function (xhr) {
console.log(e);
hashChunk();
});
}
}
}
function fileInputHandler(evt) {
var files = evt.target.files;
var chunkSize = 10485760; // bytes
var start = window.performance ? performance.now() : Date.now(); // DEBUG
var onHashFile = function (digest) {
var end = window.performance ? performance.now() : Date.now(); // DEBUG
console.log(this.name, digest, (end - start) + 'ms'); // DEBUG
};
for (var i = 0, len = files.length; i < len; i++) {
hashFile(files[i], chunkSize, onHashFile);
}
}
document.getElementById('file1')
.addEventListener('change', fileInputHandler, false);
});
and here is the embedded server code to get the request:
var stream = request.GetRequestStream();
using (var streamReader = new MemoryStream())
{
stream.CopyTo(streamReader);
videoTemp = streamReader.ToArray();
}
using (var fileStream = new FileStream(path, FileMode.Append))
{
fileStream.Write(videoTemp, 0, videoTemp.Length);
}
By the way:
For IE: If I enabled "Access data sources across domains" from setting security, then it works without error in IE.
For Chrome: If I start chrome with --disable-web-security parameter it works without error in Chrome. But I have find the solution from code.
May be this problem is on the client side browser. For example, Google Chrome is blocked cross-origin by default. To allow it you may use plugin: https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi
I have found the solution, if anyone needs it;
I have used http://nancyfx.org/ Nancy.Hosting.Self library for embedded http server, Here I was able to add "Access-Control-Allow-Origin" to response.Headers so that I could transfer file without error.