Image Preloader Callback firing before all images have loaded - javascript

Problem:
I am trying to do image preloading and found this awesome solution which I have tried to adapt.I took the code and wrapped it in a function which returns a promise, but i noticed that the done() handler was getting called before all the images were loaded, what am I doing wrong?
Code:
function preload(args) {
var $defer = $.Deferred();
var preload = args;
var promises = [];
for (var i = 0; i < preload.length; i++) {
(function(url, promise) {
var img = new Image();
img.onload = function() {
promise.resolve();
console.log("loaded:" + url);
};
console.log("loading:" + url);
img.src = url;
})(preload[i], promises[i] = $.Deferred());
}
$.when.apply($, promises).done(function() {
console.log("All images ready sir!");
$defer.resolve();
});
return $defer;
}
var images = ['https://pbs.twimg.com/media/CbM1w65UcAAKfSJ.jpg', 'https://www.kenrockwell.com/nikon/d600/sample-images/600_0985.JPG', 'https://developer.nvidia.com/sites/default/files/akamai/gameworks/blog/GameWorks_Vulkan_and_OpenGL_Samples/vulkan2.png', 'https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcSKJ1fJHxLQ6unFkHZnHJoT-RfqrBvWMrzhmRFAPUt0VvdvZSDd', 'https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcTyvamruO8NCTeQJXtQaXM8xEQS5P9ANh_npfgZpv-7x8ISvzX5zg'];
preload(images).done(function() {
console.log("OK, begin business process..");
});
Console Output:
JSFIDDLE:
https://jsfiddle.net/sajjansarkar/f5k94n2r/

Swap these two lines
promise.resolve();
console.log("loaded:" + url);
The promise is resolving which triggers the rest of the resolve chain. Then the log message is added.

Related

Trouble with running function before FileReader

I've got some code running within a Vue.js component, but I get the following error:
TypeError: Cannot read property 'then' of undefined
I just want to run loadingAnimation() before the filereading, but searching on the internet for this error didn't really help me. What is the best way of doing this?
This is my code:
openFileBrowse() {
var vm = this;
var input = document.getElementById("filebutton");
if (input.files[0].type != "application/vnd.ms-excel"){
alert("You have uploaded a wrong file type. We require a .csv file not a " + input.files[0].type + " file.");
} else {
//Update loader text
vm.updateLoader('parsing csv');
//Start loadscreen
vm.loadingAnimation().then(function () {
//Start reading data
var reader = new FileReader();
var csvData = "";
var jsonData;
var iconv = require('iconv-lite');
reader.onload = function(){
csvData = iconv.decode(reader.result, 'latin1');
jsonData = vm.tsvJSON(csvData);
vm.addFiles(jsonData);
};
reader.onloadend = function(){
//Go to visualization page
router.push({ name: 'Visualization' });
};
reader.readAsText(input.files[0]);
});
}
},
loadingAnimation() {
//Make loading screen visible with animation
var target = document.getElementById('loadBox');
target.classList.remove('hidden')
setTimeout(function () {
target.classList.remove('visuallyhidden');
}, 20);
}
loadingAnimation isn't an async function and doesn't explicitly return a promise, so calling it doesn't give you a promise. In fact, it doesn't have any explicit return value, so calling it will always give you undefined.
If you want it to return a promise that will be fulfilled when the timer callback is fired, you have to code it. For instance:
loadingAnimation() {
return new Promise(resolve => {
//Make loading screen visible with animation
var target = document.getElementById('loadBox');
target.classList.remove('hidden')
setTimeout(function () {
target.classList.remove('visuallyhidden');
resolve();
}, 20);
});
}

waiting for Base64 image to return value in javascript async loop

I'm having a nightmare getting an async loop to work.
I need to retreive an image as data to do something with BUT all I can return is 'undefined' and it doent wait for that result!!
Simply put I need to retreive the data image and pass it to the next function but cant get it to wait!!
heres the code
function getImages(aID){
async function getFileContentAsBase64(path, callback){
window.resolveLocalFileSystemURL(path, gotFile, fail);
function fail(e) {
alert('Cannot found requested file');
}
function gotFile(fileEntry) {
fileEntry.file(function(file) {
var reader = new FileReader();
reader.onloadend = function(e) {
var content = this.result;
console.log('content looks as it should:::', content);
callback(content);
};
reader.readAsDataURL(file);
});
}
}
console.log("aData uploadImages:", aData);
console.log("aData.length:", aData.length);
(async () => {
console.log("in sync length:::" + aData.length);
for (let i = 0; i < aData.length; i++) {
console.log("in loop:::")
// toastSuccess("fetching image.--.")
var fileURL = 'filepath/filename.jpg';
console.log(i + "-LOOKING FOR:::", fileURL);
const getImage = await getFileContentAsBase64(fileURL, function(base64Image {//<<<<HERE HERE HERE --THIS IS THE ISSUE
console.log("base64Image LOOKS AS IT SHOULD:::", base64Image);
});
console.log(i + "-IMAGEDATA COMES back as undefined", getImage);//<<<HERE HERE HERE - this is the issue. I need to get this value before the loop continues!!!
console.log(i + "-s::: GOT IMAGE");
// toastSuccess("sending image. .-")
var oParams = {id:1}//,body:getImage
var sendImage = await doSomethingElse(getImage, oParams);
}
})();
}
got it: it needed a promise, also removed the async from "function getFileContentAsBase64(. ." at the top of the page
const getImage = new Promise((resolve, reject) => {
getFileContentAsBase64(sfileURL, function(base64Image){ resolve(base64Image); reject('error on return');})
});
thanks .--. . .- -.-. .

Issue with syntax for javascript promise

I am using pdfjs to read a pdf file and get its pages as images. After all the images are loaded, I need to call an ajax to send and get details from the server. The code for iterating pages in the pdf has been taken from here: https://ourcodeworld.com/articles/read/405/how-to-convert-pdf-to-text-extract-text-from-pdf-with-javascript
I am having problem writing the syntax for the promise that will call the ajax function after all the required details mentioned above has been fetched.
Here is my code:
getDataUrlsAndSizesFromPdf(file).then(proceedAndCheckOnServer(file));
const getDataUrlsAndSizesFromPdf = function(file) {
PDFJS.disableWorker = true;
fileReader = new FileReader();
fileReader.readAsArrayBuffer(file);
return new Promise(function(resolve, reject) {
fileReader.onload = function(ev) {
PDFJS.getDocument(fileReader.result).then(function (pdf) {
var pdfDocument = pdf;
var pagesPromises = [];
for (var i = 0; i < pdf.pdfInfo.numPages; i++) {
var pageNum = i + 1;
pagesPromises.push(getImageUrl(pageNum, pdfDocument));
}
Promise.all(pagesPromises).then(function () {
console.log(pdfPagesInfo);
resolve();
}, function () {
console.log('failed');
reject();
});
}, function (reason) {
console.error(reason);
});
}
});
}
function getImageUrl() {
return new Promise(function (resolve, reject) {
PDFDocumentInstance.getPage(pageNum).then(function (pdfPage) {
var scale = 1;
var viewport = pdfPage.getViewport(scale);
var canvas = document.getElementById('dummy-canvas');
var context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
var task = pdfPage.render({canvasContext: context, viewport: viewport})
task.promise.then(function(){
var sizesArr = {
height : viewport.height,
width : viewport.width
}
pdfPagesInfo.sizes[pageNum.toString()] = sizesArr
pdfPagesInfo.images[pageNum.toString()] = canvas.toDataURL('image/jpeg');
resolve();
});
});
});
}
function proceedAndCheckOnServer() {
....
}
What I want is "proceedAndCheckOnServer()" to be executed when all the details have been fetched from "getImageUrl()". But presently the execution directly goes to "proceedAndCheckOnServer()" without waiting for the promise from "getDataUrlsAndSizesFromPdf" to be resolved. I am new to javascript promises. Please help me with the syntax.
You are calling your function instead of using a callback function.
proceedAndCheckOnServer is invoked, and the result of that function is used as the parameter to then.
getDataUrlsAndSizesFromPdf(file).then(proceedAndCheckOnServer(file));
Try one of these:
getDataUrlsAndSizesFromPdf(file).then(()=>proceedAndCheckOnServer(file));
getDataUrlsAndSizesFromPdf(file).then(function(){ proceedAndCheckOnServer(file) });
Or resolve your getDataUrlsAndSizesFromPdf promise with file and use the function without () to pipeline the result.
getDataUrlsAndSizesFromPdf(file).then(proceedAndCheckOnServer);

JavaScript - Timing Issue - How to wait on Request

I have an Image that needs to be displayed based on the outcome of the AJAX Call. I don't load the jQuery and other Libraries like Foundation which is responsible for loading responsible image based on the device.
The response time of the AJAX call ranges from 800-1000 ms. If the response takes more than 1000 ms I would display a default image. Also I should send the AJAX request as the first request on load , hence it is set immediately as the first child of header.
JSFiddle for Timing issue
<html><head><script>set Timeout of 1000 ms .....xhr.send();</script>
<body>
<div id="id_in_response" style="display:none"><img src="xyz"></div>
<div id="default_on_timeout" style="display:none"><img src="xyz"></div>
....Loads of Elements.....
<footer>
<script src="jquery.js"></script>
<script src="foundation.js"></script>
<script src="custom.js"></script>
</body>
Explanation of custom js :
Custom js will execute a Foundation library js to load the responsive image.
The problem is how should the XHR communicate with custom.js function that there is either a TIMEOUT OR Response has to be processed. I cannot use jQuery Promise because the jQuery will load after the HTML is downloaded. I cannot use Native Promises yet .
It can be that while the XHR response comes in , but the custom.js has still not loaded or getting parsed. I also cannot assume that resonse time will be always be in the range of 800-1000 ms. It can even come down to 300 ms or less.
Custome JS code :
$(document).foundation({interchange : named_queries {....}});
// This will parse all the image tags , Run media Query and attach an
appropriate source to the image
Final Solution : enter link description here
poor mans "future" code
var specialRequest = (function() {
var cb;
var cberr;
var xhr = new XMLHttpRequest();
var doCallback = function(err) {
if (cb === undefined) {
cb = true;
cberr = err;
} else if (typeof cb === 'function') {
cb(err, xhr);
}
};
var timeout = setTimeout(function() {
xhr.abort(); //??
doCallback('timeout');
}, 1000);
xhr.open('GET', 'whatever/your/url/is');
xhr.onload = function() {
doCallback(null);
}
xhr.onerror = function() {
doCallback('error');
}
xhr.onloadend = function() {
// if the XHR finishes before the setTimeout, cancel it
clearTimeout(timeout);
}
xhr.send();
return function(callback) {
if (cb === undefined) {
cb = callback;
} else if (cberr !== null) {
callback(cberr, xhr);
}
}
})();
and then, in custom.js
specialRequest(function(error, xhr) {
if (error) {
// handle error
} else {
// handle success
}
});
compare this with Promise code
var myPromise = new Promise(function(resolve, reject) {
var xhr = new XMLHttpRequest();
var timeout = setTimeout(function() {
reject(new Error('timeout'));
}, 1000);
xhr.open('GET', 'whatever/your/url/is');
xhr.onload = function() {
resolve(xhr);
}
xhr.onerror = function() {
reject(new Error('error'));
}
xhr.send();
});
// in custom.js
myPromise.then(function(xhr) {
// handle success
}).catch(function(reason) {
// handle failure
});
should i use setInterval - wouldnt that block the page ?
No, it wouldn't; but you'd use setTimeout, not setInterval, to establish your 1000ms timeout. E.g., roughly:
var timer = setTimeout(function() {
// Use default image instead
}, 1000);
var xhr = new XMLHttpRequest(/*...*/);
xhr.send(/*...*/);
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
if (/*...you haven't already used the default image...*/) {
clearTimeout(timer);
// Use the appropriate image...
}
}
};
Note that the above doesn't hold up the display of the page, which I strongly recommend not doing. Just fill in the image when you know what image to fill in (as above).

HTML5 FileReader in Opera

I am trying to read multiple local ogg audio files using the file reader api in opera 12 by converting them into data urls and storing them into an array which I intend to access later.
function music(list)
{
var playlistlength=0;
try
{
for (var temp=0; temp < list.files.length; temp++)
{
f[playlistlength][0] = list.files.item(temp).name;
var freader = new FileReader();
freader.onload = function(frevent){
f[playlistlength][1]=frevent.target.result;
};
freader.readAsDataURL(list.files[temp]);
playlistlength++;
}
}
catch(e)
{
alert("Error");
}
}
However upon inspection in the debugger, in the for loop , no statement is executed and it jumps to the catch block, unable to figure it out.Can someone explain why its happening and any alternatives if possible? Thanks in advance.
This works on jsFiddle. I made it from your code, is your use of it similar ?
HTML :
​<input type="file" id="browser"/>​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
Javascript :
function music(list)
{
var playlistlength=0;
var f = new Array();
try
{
for (var temp=0; temp < list.files.length; temp++)
{
var music = new Array();
music[0] = list.files.item(temp).name;
var freader = new FileReader();
freader.onload = function(frevent){
music[1]=this.result;
f.push(music);
alert(f);
};
freader.readAsDataURL(list.files[temp]);
playlistlength++;
}
alert(f);
}
catch(e)
{
alert(e);
}
}
function FileSelectHandler(e) {
var list = e.target || e.originalEvent.dataTransfer;
music(list);
}
document.getElementById("browser").onchange = FileSelectHandler;
Why it didn't work ?
First you tried to set a value in f[playlistlength][1], because of
the onload function asynchronously executing after the
playlistlength++. It crashed because this reference didn't exist.
f was probably wrong declared ​

Categories