Promise .then() chains: second .then run before the first?? o.0 - javascript

I'm trying to create a new File object from blob data in a .then structure, and after in the second .then, read info of this file.
But the second then run before the first end, so the file object isn't filled yet.
Is that a normal behavior? Should I make an async function, called in the first then to ensure the second one is strictly called after?
let output = {file: {}, file_infos: {}},
image = FileAPI.Image(src_file);
await Promise.all(Object.keys(parameters).map(async (parameter_name) => { // Pass file threw all modifiers (resizing, rotation, overlaying)
try {
image = await FileMethods[parameter_name](image, parameters[parameter_name]);
return image;
}
catch(err) {
console.log(err);
};
}))
.then((output_image) => {
output_image[0].toBlob((blob) => {
output.file = new File([blob], src_file.name); // Need this to be fullfilled before step2
console.log('step1');
});
})
.then(() => {
console.log('step2');
FileAPI.getInfo(output.file, (err/**String*/, infos/**Object*/) => {
if( !err ){
output.file_infos = infos;
} else {
console.log("this is triggered because output.file isn't filled yet");
}
})
});
// console.log(output);
return output;
console shows me:
step2
this is triggered because output.file isn't filled yet
step1
Thanks for helps :)

The two asynchronous functions in the two .then's do not return a Promise, so first they need to be "Promisified", also, since you're already using async/await don't use a promise .then chain
const image = FileAPI.Image(src_file);
const output_image = await Promise.all(Object.keys(parameters).map(async(parameter_name) => {
try {
image = await FileMethods[parameter_name](image, parameters[parameter_name]);
return image;
} catch (err) {
console.log(err);
};
}));
const file = await new Promise((resolve, reject) => output_image[0].toBlob((blob) =>
resolve(new File([blob], src_file.name))
));
const file_infos = await new Promise((resolve, reject) => FileAPI.getInfo(file, (err, file_infos) => {
if (!err) {
resolve(file_infos);
} else {
reject("this is triggered because output.file isn't filled yet");
}
));
return {file, file_infos};
A note about
const output_image = await Promise.all(Object.keys(parameters).map(async(parameter_name) => {
try {
image = await FileMethods[parameter_name](image, parameters[parameter_name]);
return image;
} catch (err) {
console.log(err);
};
}));
you're essentially doing return await FileMethods[parameter_name](image, parameters[parameter_name]) - so, you really don't need in this case an async/await pattern, just return the Promise in the .map
const output_image = await Promise.all(Object.keys(parameters).map((parameter_name) =>
FileMethods[parameter_name](image, parameters[parameter_name]);
));
Or, even nicer (in my opinion)
const output_image = await Promise.all(Object.entries(parameters).map((p_name, p_value) =>
FileMethods[p_name](image, p_value)
));
Alternatively, to use Promise .then chains and no async/await
const image = FileAPI.Image(src_file);
return Promise.all(Object.keys(parameters).map(parameter_name => FileMethods[parameter_name](image, parameters[parameter_name])))
.then(output_image => new Promise((resolve, reject) => output_image[0].toBlob((blob) =>
resolve(new File([blob], src_file.name))
)))
.then(file => new Promise((resolve, reject) => FileAPI.getInfo(file, (err, file_infos) => {
if (!err) {
resolve({file, file_infos});
} else {
reject("this is triggered because output.file isn't filled yet");
}
)));

.toBlob() returns instantly because it uses the asynchronous callback pattern.
What you want is to return a promise that resolves when the work is done. So you could do something like this:
.then((output_image) => {
return new Promise((res, rej) => {
output_image[0].toBlob((blob) => {
output.file = new File([blob], src_file.name); // Need this to be fullfilled before step2
console.log('step1');
res();
});
});
})

toBlob is probably asynchronous. Change the first .then to this:
.then((output_image) => {
return new Promise((resolve) => output_image[0].toBlob((blob) => {
output.file = new File([blob], src_file.name); // Need this to be fullfilled before step2
console.log('step1');
resolve();
}));
})

Related

Getting incorrect value when I return value from a fulfilled promise

Struggling to get a value from a promise.
When I resolve the promise and console.log the result I see this:
46 38
This is the correct value I expect to see. However, when I call the method that is supposed to return this promise (receives data from a websocket), I get this:
user id is matched_id 1096
This is my code. This is the method that receives data from my websocket:
async sendData(data){
if(this.socketRef.readyState !== WebSocket.OPEN) {
console.log('we are still waiting')
await new Promise((resolve, reject) => {
console.log('now opening websocket')
this.socketRef.addEventListener('open', resolve);
});
}
console.log('now sending', data)
this.socketRef.send(data)
const result = await new Promise((resolve, reject) => {
this.socketRef.onmessage = e => {
resolve(e.data)
}
});
console.log('what is result', result)
return String(result)
This is where this method is triggered:
function receiveWebSocketData(matchedUser, roomId){
const userID = WebSocketInstance.sendData(matchedUser+' '+roomId)
const fulfilled = userID.then((res)=> { return res })
const fulfilledPromise = setTimeout(()=>{
fulfilled.then((result)=> { return result } )
}, 5000)
return fulfilledPromise;
};
When I console.log the result from the above function this is where I receive the 1096 output.
UPDATE I have tried a solution from the answer I have received so far:
async sendData(data){
if(this.socketRef.readyState !== WebSocket.OPEN) {
console.log('we are still waiting')
await new Promise((resolve, reject) => {
console.log('now opening websocket')
this.socketRef.addEventListener('open', resolve);
});
}
console.log('now sending', data)
this.socketRef.send(data)
const result = await new Promise((resolve, reject) => {
this.socketRef.onmessage = e => {
resolve(e.data)
}
});
return String(result)
and
async function receiveWebSocketData(matchedUser, roomId){
return WebSocketInstance.sendData(matchedUser+' '+roomId);
I then tried this console.log(await receiveWebSocketData(matchedUser, roomId)
and get the error:
Unexpected reserved word 'await'.
when I try this:
console.log('what am I getting receiveWeb', receiveWebSocketData(matchedUser, roomId).then((res) => console.log(res)))
I get this:
[[Prototype]]: Promise
[[PromiseState]]: "fulfilled"
[[PromiseResult]]: undefined
That's not how promises work. Just return the promise.
function receiveWebSocketData(matchedUser, roomId){
return WebSocketInstance.sendData(matchedUser+' '+roomId);
};
To access the returned value use await or .then()
console.log(await receiveWebSocketData(matchedUser, roomId));
or
receiveWebSocketData(matchedUser, roomId).then((res) => console.log(res));

How do i write promises in javascript

im trying to write a promise but seems to be missing something. here is my code:
const myPromise = new Promise(() => {
setTimeout(() => {
console.log("getting here");
return setinputs({ ...inputs, images: imageAsUrl });
}, 100);
});
myPromise
.then(() => {
console.log("getting here too");
firebase.database().ref(`collection/${idNode}`).set(inputs);
})
.then(() => {
console.log("all is set");
})
.catch((err) => {
console.log(err);
});
if i run the program, the first part of the promise is executing but all .then() functions arent executing. how do i fix this?
In this scheme, the promise callback has one (resolve) or two (resolve,reject) arguments.
let p = new Promise((resolve, reject)=> {
//do something
//resolve the promise:
if (result === "ok") {
resolve(3);
}
else {
reject("Something is wrong");
}
});
p.then(res => {
console.log(res); // "3"
}).catch(err => {
console.error(err); //"Something is wrrong
});
Of course, nowadays you can use async + await in a lot of cases.
You need to resolve the promise, using resolve() and also return the promise from firebase so the next .then in the chain works properly.
const myPromise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("getting here");
// You have to call resolve for all `.then` methods to be triggered
resolve({ ...inputs, images: imageAsUrl });
}, 100);
});
myPromise
.then((inputs) => {
console.log("getting here too");
// You have to return a promise in a .then function for the next .then to work properly
return firebase.database().ref(`collection/${idNode}`).set(inputs);
})
.then(() => {
console.log("all is set");
})
.catch((err) => {
console.log(err);
});

How to correctly resolve a promise within promise constructor

const setTimeoutProm = (delay) => new Promise(res => setTimeout(() => res(delay),delay))
I want to do something like,
const asyncOpr = (delay) => {
return new Promise((resolve, reject) => {
//update delay for some reason.
const updatedDelay = delay * 2;
setTimeoutProm(updatedDelay).then(res => {
resolve(res);
}).catch(err => {})
})
}
asyncOpr(2000).then(() => alert("resolved")) //this works
This works as expected, but I am not sure if this is correct way of doing this or is there any better way of doing this ?
No, actually the way you do it is an antipattern.
You can just return a promise from the function:
const asyncOpr = (delay) => {
return setTimeoutProm(delay);
};
If needed, a Promise could also be returned from inside a .then:
doA()
.then(() => setTineoutProm(1000))
.then(() => doB());
Or it can also be awaited inside an async function:
async function asyncOpr(delay) {
//...
await setTimeoutProm(delay);
//...
}

Nested Promises, And Another After Completion [duplicate]

I have a situation where I think the only choice for me is to nest some Promises within each other. I have a Promise that needs to be performed and a method that does something until that Promise is complete. Something like this:
let promise = new Promise((resolve, reject) => {
// Do some stuff
});
doSomethingUntilPromiseisDone(promise);
However, within my Promise, I need to execute another method that returns another Promise:
let promise = new Promise((resolve, reject) => {
fetchValue(url)
.then((value) => {
// Do something here
}).catch((err) => {
console.error(err);
});
});
doSomethingUntilPromiseisDone(promise);
But now, in the fetchValue method's then statement, I have another method I need to execute that, guess what, returns another Promise:
let promise = new Promise((resolve, reject) => {
fetchValue(url)
.then((value) => {
saveToCache(value)
.then((success) => {
console.log('success!!');
resolve('success');
});
}).catch((err) => {
console.error(err);
});
});
doSomethingUntilPromiseisDone(promise);
So in the end, I have a Promise, within a Promise, within a Promise. Is there someway I can structure this better so that it is more straightforward? It seems like nesting them within each other is counter to Promise's intended chaining approach.
Use .then()
let doStuff = (resolve, reject) => {/* resolve() or reject() */};
let promise = new Promise(doStuff);
doSomethingUntilPromiseisDone(
promise
.then(value => fetchValue(url))
.then(value => value.blob())
.then(saveToCache)
)
.then(success => console.log("success!!"))
.catch(err => console.error(err))
you can use generator to flatten your nested promises (Bluebird.couroutine or Generators)
//Bluebird.couroutine
const generator = Promise.coroutine(function*() {
try {
const value = yield fetchValue(url);
const success = yield saveToCache(value);
console.log('success:', success);
} catch(e) {
console.error(err);
}
}));
generator();
Each function will call the next one with the result of the method before.
var promises = [1,2,3].map((guid)=>{
return (param)=> {
console.log("param", param);
var id = guid;
return new Promise(resolve => {
// resolve in a random amount of time
setTimeout(function () {
resolve(id);
}, (Math.random() * 1.5 | 0) * 1000);
});
}
}).reduce(function (acc, curr, index) {
return acc.then(function (res) {
return curr(res[index-1]).then(function (result) {
console.log("result", result);
res.push(result);
return res;
});
});
}, Promise.resolve([]));
promises.then(console.log);

Wait for promises inside Promise.all to finish before resolving it

I have a Promise.all that executes asynchronous functions mapped on an array input if it's not null and then resolve data to a previously defined Promise:
Promise.all((inputs || []).map(input => {
return new Promise((resolve, reject) => {
someAsyncFunc(input)
.then(intermediateOutput => {
someOtherAsyncFunc(intermediateOutput )
.then(output => {
return Promise.resolve(output )
})
.catch(reason=> {
return Promise.reject(reason)
})
})
.catch(reason => {
return Promise.reject(reason);
})
})
.then(outputs => {
resolve(outputs)
})
.catch(reason => {
reject(reason)
})
}))
I only get empty outputs before even someAsyncFunc finishes its work. How can make Promise.all wait for the promises inside to finish their asynchronous work ?
Would not just
return Promise.all((inputs || []).map(input =>
somePromiseFunc(input).then(someOtherPromiseFunc)
);
work ?
You're not using Promise.all right the first time since it takes an array of promises as input, and not (resolve, reject) => { ... }
Promise.all is going to be rejected as soon as one of the underlying promises fails, so you don't need to try to do something around catch(error => reject(error)
Example:
const somePromiseFunc = (input) => new Promise((resolve, reject) => {
setTimeout(() => {
if (input === 0) { reject(new Error('input is 0')); }
resolve(input + 1);
}, 1000);
});
const someOtherPromiseFunc = (intermediateOutput) => new Promise((resolve, reject) => {
setTimeout(() => {
if (intermediateOutput === 0) { reject(new Error('intermediateOutput is 0')); }
resolve(intermediateOutput + 1);
}, 1000);
});
const f = inputs => {
const t0 = Date.now()
return Promise.all((inputs || []).map(input => somePromiseFunc(input).then(someOtherPromiseFunc)))
.then(res => console.log(`result: ${JSON.stringify(res)} (after ${Date.now() - t0}ms)`))
.catch(e => console.log(`error: ${e} (after ${Date.now() - t0}ms)`));
};
f(null)
// result: [] (after 0ms)
f([1, 0])
// error: Error: input is 0 (after 1001ms)
f([1, -1])
// error: Error: intermediateOutput is 0 (after 2002ms)
f([1, 2])
// result: [3,4] (after 2002ms)
See jfriend's comment.
someAsyncFunc and someOtherAsyncFunc are function that properly return a promise
with something like return new Promise(/*...*/);
this is useless:
.then(output => {
return Promise.resolve(output )
})
read the Promise documentation
same
.catch(reason=> {
return Promise.reject(reason)
})
the Promise is already rejecting, you don't need to catch and reject yourself
to make sure Promises are chainable you need to return the Promise
// ...
return new Promise((resolve, reject) => {
if(inputs == null)
resolve([]);
else {
Promise.all(inputs.map(input => {
return someAsyncFunc(input)
.then(someOtherAsyncFunc)
}))
.then(resolve)
.catch(reject)
}
});
note I would rather not make the arry for Promise.all inline, it adds visual clutter:
return new Promise((resolve, reject) => {
if(inputs == null)
resolve([]);
else {
const myPromises = inputs.map(input => {
return someAsyncFunc(input)
.then(someOtherAsyncFunc)
});
Promise.all(myPromises)
.then(resolve)
.catch(reject)
}
});
it may still fail if you made other mistakes.

Categories

Resources