Incremental loading of images with promises - javascript

I am trying to load same image but with different resolution, one by one, with 1.png first and then 2.png and then 3.png, with help of promises, but when i run the code, it loads only 3.png image, what am i doing wrong?
function loadi(srce){
if(srce!='3.png'){
$img1.attr('src',srce).on('load',function(){
return loadImag();
});
}
else{
$img1.attr('src',srce).on('load',function(){
console.log("Load successful");
});
}
}
function loadImag(){
return new Promise(function(fulfill,reject){
fulfill();
});
}
loadImag()
.then(loadi('1.png'),null)
.then(loadi('2.png'),null)
.then(loadi('3.png'),null);
New code after 1st suggestion, still facing the same issue, only one image being loaded as seen in chrome dev tools
function loadi(srce){
return loadImage(srce);
}
function loadImage(src) {
return new Promise(function(resolve, reject) {
$img1.attr('src',src).on('load',function(error){
resolve();
});
// Run image loading logic here
// Call resolve() when loading complete, or reject() when fails.
});
}
loadImage('1.png')
.then(loadi('2.png'))
.then(loadi('3.png'))
.then(function() {
console.log('Load successful!');
}) // Not in loadImage().
.catch(function(err) {
console.log("Error");/* Handle potential errors */
});

Few things wrong with your code:
loadi does not return a Promise. Returning from a callback doesn't work as expected.
loadImag can basically be replaced with Promise.resolve().
.then() is expecting a function, you're passing the result of the function.
Your code should look like this:
function loadImage(src) {
return new Promise(function(resolve, reject) {
// Run image loading logic here
// Call resolve() when loading complete, or reject() when fails.
)};
}
loadImage('1.png')
.then(function() { return loadImage('2.png'); })
.then(function() { return loadImage('3.png'); })
.then(function() { console.log('Load successful!'); }) // Not in loadImage().
.catch(function(err) { /* Handle potential errors */ });

Related

check if all asynchronous http requests are done

So I have multiple asynchronous HTTP requests in my pure JS app, but while they load they block the effective work with the app. I want to show a loading indicator for that, I have no idea how I can do it with asynchronous requests.
What I tried.
I checked how many requests I fired in an array while these are not done I showed a loading indicator, but because these are asynchronous after the first set was done there came in another set, because of dependencies to each other.
Is there something to solve this problem?
Lets assume you have code like so:
function doAjax(params, callback) {
// ...
callback(ajaxResponse, error);
}
function doRequests() {
doAjax(params, (success, error) => {
if(error) console.error(error);
console.log(success);
});
doAjax(params2, (success, error) => /* ... */);
// ...
}
You can easily rewrite that into Promises:
function doAjax(params) {
return new Promise((resolve, reject) => {
// ...
if(error) reject(error);
else resolve(ajaxResponse;
});
}
function doRequests() {
showLoader();
Promise.all(doAjax(params), doAjax(params2), /* ... */)
.then((results) => {
console.log(results);
hideLoader();
})
.catch(error => {
console.error(error);
hideLoader();
});
}

Promise resolves before forEach loop completes

I'm building my first CRUD (library) application and recently learned about promises as a means to avoid deeply-nested callbacks. I'm attempting to seed my DB with some data each time the server starts, but I seem to be missing something conceptually.
I have four objects in a bookData array that I want to iterate over and save to the DB using Mongoose:
function seedBooks() {
return new Promise(function(resolve,reject){
bookData.forEach(function(seed){
Book.create(seed, function(err, newBook){
if(err) {
reject(err);
}
});
});
resolve();
});
}
This function is one of a few that I am attempting to chain together, which is why I'm using promises. But I'm finding that seedBooks() resolves with anywhere between 1 and 4 of the sample books created,
function seedDB() {
removeAllBooks()
.then(function(){
return removeAllUsers();
})
.then(function(){
return seedUsers();
})
.then(function(){
return seedBooks();
})
.then(function(){
return seedBookInstances();
});
}
Am I understanding or using promises & resolve incorrectly? Any help is appreciated. Thanks!
Edit: The below explains why your code is not working and advice for, in general, how to convert non-promise code to promises. Since Mongoose produces promises, however, you should be using those instead of using new Promise. See Olegzandr's answer regarding that.
The promise is resolving immediately because you are calling resolve() immediately.
The rule of thumb when converting non-promises to promises is to promisify the smallest part of the non-promise code. In this case, it means promisifying the code to save a single item. If you do that, the collect place to call resolve() becomes clear:
function seedBook(seed) {
return new Promise(function (resolve, reject) {
Book.create(seed, function (err, newBook) {
if (err) { reject(err); } else { resolve(newBook); }
});
});
}
function seedBooks() {
return Promise.all(bookData.map(seedBook));
}
This also has the benefit of allowing you to access the returned newBooks, should you want to.
If you are using Mongoose, you can just do this:
const saveBooks = function(books) {
return books.map(function(seed) {
return Book.create(seed); // returns a promise
});
});
}
return Promise.all(saveBooks(books)).then(function(){
// all books are saved
});
You are resolving your Promise synchronously, right after you started your forEached requests, which are async. You may try the following approach instead:
function seedBooks() {
return new Promise(function(resolve,reject){
var count = 0, length = bookData.length;
bookData.forEach(function(seed){
Book.create(seed, function(err, newBook){
if(err) {
reject(err);
return;
}
if(count++ >= length ) {
resolve();
}
});
});
});
}
Here the Promise is being resolved only after all async requests are done.
Another option would be just to use Promise.all. In that approach you need to promisify all your requests in the loop, return an array of Promises and then call Promise.all(_seedBooks()).then(), where _seedBook returns an array of Promises:
function _seedBooks() {
return bookData.map(function(seed) {
return new Promise(function(resolve, reject) {
Book.create(seed, function(err, newBook) {
if(err) {
reject(err);
return;
}
resolve(newBook);
});
});
});
}
Promise.all(_seedBooks())
.then(function(result) { /* result is the array of newBook objects */ })
.catch(function(error) { /* error is the first rejected err */ })

How can I prevent calling the API multiple times?

I have the following function
$(window).localDatabase('schooldata', schoolId)
which either returns a stored value or, if outdated, calls the following
return new Promise(function(resolve, reject){
console.log('Downloading school database');
axios.get('/api/school-database/'+schoolId+'/schooldata')
.then(response => {
$(window).storage(
'planner',
'save',
'schooldata-'+schoolId,
[response.data]
).then(function(response2){
resolve(response.data);
saveLastUpdate('schooldata-'+schoolId).then(function(response2){
triggerOnVueBus('db-updated:schooldata');
});
});
});
});
The code works flawlessly, except I have many Vue components that require the database and on startup call multiple times the Promise i pasted.
I would like to implement a method which does not make another request if one is pending already: what logic should I follow?
I think this should work. Create promise once and always return the same promise. If a promise is already resolved, the .then block is triggered immediately with already resolved value. Something like this:
if (!this.promise) {
this.promise = new Promise(function(resolve, reject) {
console.log('Downloading school database');
axios.get('/api/school-database/' + schoolId + '/schooldata')
.then(response => {
$(window).storage(
'planner',
'save',
'schooldata-' + schoolId, [response.data]
).then(function(response2) {
resolve(response.data);
saveLastUpdate('schooldata-' + schoolId).then(function(response2) {
triggerOnVueBus('db-updated:schooldata');
});
});
});
});
}
return this.promise;

Javascript - code not stoping in then

I am trying to expand my knowledge (beginner stage). Basically, I would like to use promises to write new email to my user. I have some code base in my play ground project, but my function is not stopping on then.
This is the function that should write to Database:
changeEmailAddress(user, newEmail) {
new Promise((resolve, reject) => {
user.setEmail(newEmail);
userRepository.saveUser(user).then(() => {
return resolve();
}).catch(e => {
return reject(e);
});
}
);
}
And if I am not mistaken, this is how I should use it:
changeEmailAddress(user, "hello#there.com").then(function () {
//it never comes in here :(
})
I have similar functions working on the user, but my function is not coming in to 'then'
You're committing the explicit promise constructor anti-pattern. Your code need be no more complicated than
changeEmailAddress(user, newEmail) {
user.setEmail(newEmail);
return userRepository.saveUser(user);
}
Making sure, of course, to not forget the return!
You are not returning the new Promise.
changeEmailAddress(user, newEmail) {
return new Promise((resolve, reject) => {
user.setEmail(newEmail);
userRepository.saveUser(user).then(() => {
resolve();
}).catch(e => {
reject(e);
});
});
}
You may also have an unhandled rejection.
changeEmailAddress(user, "hello#there.com").then(function () {
//it never comes in here :(
}).catch(function(e) {
console.log(e); // Does this happen?
})
EDIT: Your changeEmailAddress uses the anti-pattern (see #torazburo's answer). Although this answer works, you should just return your saveUser promise unless you want to directly work with the result of it.
your function changeEmailAddress return nothing, that's why
changeEmailAddress(user, newEmail) {
let promise = new Promise((resolve, reject) => {
user.setEmail(newEmail);
userRepository.saveUser(user).then(() => {
return resolve();
}).catch(e => {
return reject(e);
});
});
return promise;
}

Waiting for an optional process operation inside bluebird promise

I have a bluebird promise, which runs a check. If this check is true, it can continue on. However, if this check is false, it needs to spawn an asynchronous process, which it must wait to complete before continuing.
I have something like the following:
var foo = getPromise();
foo.spread( function (error, stdout, stdin) {
if (error) {
// ok, foo needs to hold on until this child exits
var child = spawn(fixerror);
child
.on('error', function (e) {
//I need to error out here
})
.on('close', function (e) {
//I need to have foo continue here
});
} else {
return "bar";
}
});
How would I go about doing that?
First off why does your .spread() handler take a callback with error as the first argument. That does not seem correct. An error should cause a rejection, not a fulfillment.
But, if that was indeed the way your code works, then you just need to return a promise from within your .spread() handler. That promise will then get chained to the original promise and you can then see when both are done:
getPromise().spread( function (error, stdout, stdin) {
if (error) {
// ok, foo needs to hold on until this child exits
return new Promise(function(resolve, reject) {
var child = spawn(fixerror);
child.on('error', function (e) {
//I need to error out here
reject(e);
}).on('close', function (e) {
// plug-in what you want to resolve with here
resolve(...);
});
});
} else {
return "bar";
}
}).then(function(val) {
// value here
}, function(err) {
// error here
});
But, probably, your .spread() handler should not have the error argument there and that should instead cause a rejection of the original promise:
getPromise().spread( function (stdout, stdin) {
// ok, foo needs to hold on until this child exits
return new Promise(function(resolve, reject) {
var child = spawn(fixerror);
child.on('error', function (e) {
//I need to error out here
reject(e);
}).on('close', function (e) {
// plug-in what you want to resolve with here
resolve(...);
});
});
}).then(function(val) {
// value here
}, function(err) {
// error here
});
wrap the spawn or any other alternative route in promise function, then keep the flow as, (sample code):
promiseChain
.spread((stderr, stdout, stdin) => stderr ? pSpawn(fixError) : 'bar')
.then(...
// example for promisified spawn code:
function pSpawn(fixError){
return new Promise((resolve, reject) => {
spawn(fixError)
.on('error', reject)
.on('close', resolve.bind(null, 'bar'))
})
}

Categories

Resources