Last active
June 17, 2021 16:41
-
-
Save ve3/203fa29e9461d84abab9728beea8846b to your computer and use it in GitHub Desktop.
Ajax (XHR) with max concurrent connection.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--demo1-max-concurrent-wait-all.html--> | |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>XHR multi concurrent connection</title> | |
<style> | |
#debug { | |
border: 3px dashed #ccc; | |
margin: 10px 0; | |
padding: 10px; | |
} | |
</style> | |
</head> | |
<body> | |
<form id="upload-form" method="post"> | |
<input type="hidden" name="hidden-name" value="hidden-value (unnecessary)"> | |
<button type="submit">Submit</button> | |
<div id="debug"></div> | |
</form> | |
<script src="xhr.js"></script> | |
<script type="application/javascript"> | |
let debugElement = document.getElementById('debug'); | |
const thisForm = document.getElementById('upload-form'); | |
const maxConcurrentConnection = 3; | |
thisForm.addEventListener('submit', (event) => { | |
event.preventDefault(); | |
let loopPromise = Promise.resolve(); | |
let ajaxCons = []; | |
for (let i = 0; i < 10; i++) { | |
loopPromise = loopPromise.then(() => { | |
if (ajaxCons.length < maxConcurrentConnection) { | |
debugElement.insertAdjacentHTML('beforeend', '<p>Calling to server round '+ i + '. (number from JavaScript.)</p>'); | |
ajaxCons.push( | |
XHR('server.php?round=' + i) | |
.then((responseObject) => { | |
const response = responseObject.response; | |
debugElement.insertAdjacentHTML('beforeend', '<p> > Response from server: Round: <code>' + response.round + '</code></p>'); | |
return Promise.resolve(); | |
}) | |
.catch((responseObject) => { | |
console.warn('response: ', responseObject); | |
debugElement.insertAdjacentHTML('beforeend', '<p style="color: red;"> > Error! see console.</p>'); | |
return Promise.reject(); | |
}) | |
.finally(() => { | |
}) | |
); | |
if ((parseInt(ajaxCons.length)) === parseInt(maxConcurrentConnection)) { | |
return new Promise((resolve, reject) => { | |
Promise.all(ajaxCons) | |
.then((value) => { | |
console.log('value', value); | |
ajaxCons = []; | |
resolve(); | |
}); | |
}); | |
} | |
} | |
}); | |
} | |
/* | |
// basic example loop make ajax call and wait until finish then next loop... | |
let loopPromise = Promise.resolve(); | |
for (let i = 0; i < 10; i++) { | |
loopPromise = loopPromise.then(() => { | |
console.log('round ' + i); | |
return new Promise((resolve, reject) => { | |
XHR('server.php?round=' + i) | |
.then((responseObject) => { | |
const response = responseObject.response; | |
console.log('response: ', response); | |
resolve(); | |
}) | |
.catch((responseObject) => { | |
console.warn('response: ', responseObject); | |
reject(); | |
}); | |
}); | |
}); | |
} | |
*/ | |
}); | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<title>XHR multi concurrent connection</title> | |
<style> | |
#debug { | |
border: 3px dashed #ccc; | |
margin: 10px 0; | |
padding: 10px; | |
} | |
</style> | |
</head> | |
<body> | |
<p>Max 3 concurrent connection, wait for any response then continue next loop.</p> | |
<form id="upload-form" method="post"> | |
<input type="hidden" name="hidden-name" value="hidden-value (unnecessary)"> | |
<button type="submit">Submit</button> | |
<div id="debug"></div> | |
</form> | |
<script src="xhr.js"></script> | |
<script type="application/javascript"> | |
let debugElement = document.getElementById('debug'); | |
const thisForm = document.getElementById('upload-form'); | |
const maxConcurrentConnection = 3; | |
thisForm.addEventListener('submit', (event) => { | |
event.preventDefault(); | |
let loopPromise = Promise.resolve(); | |
let ajaxCons = []; | |
for (let i = 0; i < 10; i++) { | |
loopPromise = loopPromise.then(() => { | |
if (ajaxCons.length < maxConcurrentConnection) { | |
debugElement.insertAdjacentHTML('beforeend', '<p>Calling to server round '+ i + '. (number from JavaScript.)</p>'); | |
ajaxCons.push( | |
XHR('server.php?round=' + i) | |
.then((responseObject) => { | |
const response = responseObject.response; | |
console.log('response from server on js round ' + i); | |
debugElement.insertAdjacentHTML('beforeend', '<p> > Response from server: Round: <code>' + response.round + '</code></p>'); | |
return Promise.resolve(responseObject); | |
}) | |
.catch((responseObject) => { | |
console.warn('response: ', responseObject); | |
debugElement.insertAdjacentHTML('beforeend', '<p style="color: red;"> > Error! see console.</p>'); | |
return Promise.reject(responseObject); | |
}) | |
); | |
console.log('pushed ajaxCons round ' + i, ajaxCons); | |
if ((parseInt(ajaxCons.length)) === parseInt(maxConcurrentConnection)) { | |
console.log('Hold for server response at least one. ------------------'); | |
return new Promise((resolve, reject) => { | |
Promise.any( | |
ajaxCons.map((promise, index) => { | |
//ajaxCons.splice(index, 1); | |
return promise; | |
}) | |
) | |
.then((value) => { | |
console.log('value', value); | |
ajaxCons.splice(0, 1); | |
resolve(); | |
}); | |
}); | |
} | |
} | |
}); | |
} | |
}); | |
</script> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// server.php | |
sleep(1); | |
$output = []; | |
$output['round'] = (int) ($_GET['round'] ?? 0); | |
header('Content-Type: application/json'); | |
echo json_encode($output); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* XHR function. | |
* | |
* You can change to use jQuery.ajax() or anything else. | |
* | |
* xhr.js | |
*/ | |
function XHR(url, formData) { | |
return new Promise((resolve, reject) => { | |
let XHR = new XMLHttpRequest(); | |
XHR.addEventListener('abort', (event) => { | |
reject({'response': '', 'status': (event.currentTarget ? event.currentTarget.status : ''), 'event': event}); | |
}); | |
XHR.addEventListener('error', (event) => { | |
reject({'response': '', 'status': (event.currentTarget ? event.currentTarget.status : ''), 'event': event}); | |
}); | |
XHR.addEventListener('timeout', (event) => { | |
reject({'response': '', 'status': (event.currentTarget ? event.currentTarget.status : ''), 'event': event}); | |
}); | |
XHR.addEventListener('load', (event) => { | |
let response = XHR.response; | |
let headers = XHR.getAllResponseHeaders(); | |
let headerMap = {}; | |
if (headers) { | |
let headersArray = headers.trim().split(/[\r\n]+/); | |
headersArray.forEach(function (line) { | |
let parts = line.split(': '); | |
let header = parts.shift(); | |
let value = parts.join(': '); | |
headerMap[header] = value; | |
}); | |
} | |
if (event.currentTarget && event.currentTarget.status >= 200 && event.currentTarget.status < 300) { | |
resolve({'response': response, 'status': event.currentTarget.status, 'event': event, 'headers': headerMap}); | |
} else { | |
reject({'response': response, 'status': event.currentTarget.status, 'event': event, 'headers': headerMap}); | |
} | |
}); | |
XHR.open('POST', url); | |
XHR.responseType = 'json'; | |
XHR.send(formData); | |
});// end new Promise | |
}// XHR |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment