codes still execute after promise reject [duplicate] - javascript

This question already has answers here:
Do I need to return after early resolve/reject?
(6 answers)
Closed 2 years ago.
I have the following codes:
function promise3() {
return new Promise((resolve, reject) => {
function1().then(() => {
resolve();
}).catch(err => {
reject(err);
console.log("after error");
});
})
}
promise3().catch(e => {
console.log(e);
});
function1 returns a promise. But when function1 fails and returns an error. I see the console.log("after error") before the console.log of the error. I though the codes after reject would not run. reject acts like a return. What is happening here then?

If you don't want to execute anything after resolve/reject you need to return them as follow.
function promise3() {
return new Promise((resolve, reject) => {
function1().then(() => (
resolve(); //change the brackets to () instead of {}
)).catch(err => {
return reject(err); //put a return keyword in front
console.log("after error");
});
})
}
promise3().catch(e => {
console.log(e);
});
(): mean that you are returning that is inside.
{}: mean that you need to do the following tasks and return nothing if there is no return statement.

Related

JS Promise function call that returns object [duplicate]

This question already has answers here:
await setTimeout is not synchronously waiting
(2 answers)
Closed last month.
I have a async fetch function that waits 2 seconds and returns a object:
async function fetch() {
var object;
await setTimeout(() => { object = { name: 'User', data: 'API Data' } }, 2000);
return object;
}
I want to display the object when the initialization is completely done (after 2 seconds)
fetch().then((val) => {
console.log("DONE!");
console.log(val.name);
}).catch((err) => {
console.log("ERROR!");
console.log(err);
});
The code prints both DONE and ERROR Cannot read properties of undefined (reading 'name')
I have tried with Promise, no luck
let promise = new Promise((resolve, reject) => {
let request = fetch();
if (request !== undefined)
resolve(request);
else
reject(request);
}).then((val) => {
console.log(val);
});
How can I properly check that fetch() has returned a value before printing without changing the inside of the function. I can delete the async and await in it but I am unable to edit it (I.E. adding a Promise inside)
Based on requirement
I can delete the async and await in it (fetch function) but I am unable to edit it (I.E. adding a Promise inside)
The only way I see is to override window.setTimeout function to make it to return a promise. That way you will be able to await it and there will be no need to modify your fetch function.
const oldTimeout = window.setTimeout;
window.setTimeout = (fn, ms) => {
return new Promise((resolve, reject) => {
oldTimeout(() => {
fn();
resolve();
}, ms);
});
};
async function fetch() {
var object;
await setTimeout(() => {
object = { name: "User", data: "API Data" };
}, 2000);
return object;
}
fetch()
.then((val) => {
console.log("DONE!");
console.log(val.name);
})
.catch((err) => {
console.log("ERROR!");
console.log(err);
});
NOTE: For anyone without this requirement - please, use other answers to this question or check await setTimeout is not synchronously waiting for additional details/explanations. This kind of overridings are very confusing due to everyone expect common and well-known functions to behavior in a way described in the docs.
You cannot await the setTimeout function, this is because your function returns undefined. You have used the promise in the wrong way. Below code will fix your issue.
function fetch() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ name: "User", data: "API Data" });
}, 2000);
});
}
fetch()
.then((val) => {
console.log("DONE!");
console.log(val.name);
})
.catch((err) => {
console.log("ERROR!");
console.log(err);
});
And remember that there is no need to change the setTimeout function.
The problem is that setTimeout does not actually return a promise, which means you cannot use await with setTimeout, that's why the var object; is returned instantly as undefined.
To solve this issue, you simply need to wrap setTimeout around a promise.
Like so:
function setTImeoutAwait(time) {
return new Promise((resolve) => {
setTimeout(resolve, time);
});
}
You can then use it like this:
async function fetch() {
var object;
await setTImeoutAwait(1000).then(() => {
object = { name: "test" };
});
return object;
}

Why returning a Promise doesn't equals a resolve/reject block? [duplicate]

This question already has answers here:
Return value from a Promise constructor
(2 answers)
Return value of Promise's resolve/reject functions
(1 answer)
Why does a Promise return an object Promise, even if I put `return` explicitly? [duplicate]
(6 answers)
Closed 1 year ago.
This works fine :
const querySources = async() => {
return new Promise((resolve, reject) => {
if (apiLinks !== undefined){
resolve();
}else{
fetchLinks()
.then(links => {
resolve(links)
})
.catch(err => {
reject(err);
})
}
});
}
But this doesn't work - and I don't understand why.
const querySources = async() => {
return new Promise((resolve, reject) => {
if (apiLinks !== undefined){
resolve();
}else{
return fetchLinks()
}
});
}
Can someone explain why ?
Thanks !

Promise not resolving before IF STATEMENT [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I'm trying to check the results of "checkWorkflow" but it seems to be running the "If" statement before checking, i think this because of my console output.
I feel like i'm doing something wrong with the promise, but i'm kinda at a lost at this point.
Console Output
Promise { pending } *When i console.log(doesWorkflowExists)
workflow already exists, please rename
error2
const createWorkflow = async (req, res) => {
try {
const doesWorkflowExists = checkWorkflow(req.name);
if (!doesWorkflowExists) {
console.log('do stuff')
}
else {
console.log('workflow already exists, please rename')
}
} catch (error) {
handleError(res, error);
console.log("error on create workflow");
}
};
vvvv checkWorkflow vvvv
const checkWorkflow = (name = '') => {
return new Promise((resolve, reject) => {
Workflow.findOne(
{
name,
},
(err, item) => {
if (err) {
console.log('error1')
return reject(buildErrObject(422, err.message));
}
if (item) {
console.log('error2')
return reject(buildErrObject(404, "WORKFLOW_ALREADY_EXISTS"));
}
resolve();
}
);
});
};
In your checkWorkflow function, you return a Promise. When you call checkWorkflow function like this :
const doesWorkflowExists = checkWorkflow(req.name);
doesWorkflowExists is a pending Promise. On the console, you can see that.
You need to "wait" until the Promise resolve the result or reject the error. Just add "await" keyword before the function call, like this:
const doesWorkflowExists = await checkWorkflow(req.name);
The rest seems to be fine, it should work :)

Run secondary action after promise regardless of outcome?

I found this previous thread (How to perform same action regardless of promise fulfilment?), but it's 5 years old and references winjs is a kludge.
What I would like to do is load a list of data elements. I've got local copies of the list and local copies of the elements -- but they may have changed on the server side.
That process should work like this: load the LIST from the database into the local storage (Comparing against the local) --> THEN load the (multiple) DATA ELEMENTS from the database that are listed in the LIST.
So if the "loadList" async function succeeds... I want to run the "loadElements" async function. If the loadList function rejects... I STILL want to run the "loadElements" function (Which fires off multiple fetch requests - one for each element).
"Use 'finally'" I hear you say... but I want to pass the results of the "loadList" resolve/reject and "loadElements" resolve/reject functions to the calling function. 'finally' doesn't receive or pass properties as far as I know.
The reason I want to pass the results to the calling function is to see if the rejection reasons are acceptable reasons and I can trust the local copy as the authoritative copy or not (for example, if the DB doesn't contain the LIST, I can trust that the local list is the authoritative version)... so I need a way to analyze the 'failures' within the calling function.
Here is what I have:
export function syncLinkTablesAndElementsWithDB(username) {
return (dispatch, getState) => {
return new Promise((resolve, reject) => {
dispatch(loadLinkTableAndElementsFromDB(STATIONS_LINK_TABLE_TYPE, username))
.then((msg) => {
console.log("loadLinkTableAndElementsFromDB RESOLVED: ", msg);
resolve(msg)
})
.then(() => {
dispatch(pushLinkTableToDB(STATIONS_LINK_TABLE_TYPE, username))
dispatch(pushAllUserStationsToDB(username))
})
.catch((allPromReasons) => {
console.log("loadLinkTableAndElementsFromDB REJECTED: ", allPromReasons);
allReasonsAcceptable = true;
allPromReasons.forEach(reason => {
if (!isAcceptableLoadFailureReasonToOverwrite(reason)) {
allReasonsAcceptable = false;
}
});
if (allReasonsAcceptable) {
//TODO: DO push of local to DB
// eventually return results of the push to DB...
} else {
reject(allPromReasons)
}
})
});
}
}
export function loadLinkTableAndElementsFromDB(tableType, username) {
return (dispatch, getState) => {
return new Promise((resolve, reject) => {
dispatch(loadLinkTableFromDB(tableType, username))
.then(successMsg => {
resolve(Promise.all([successMsg, dispatch(loadAllUsersStationsFromDB(username)).catch(err=>err)]))
})
.catch(err => {
reject(Promise.all([err, dispatch(loadAllUsersStationsFromDB(username)).catch(err=>err)]))
})
});
}
}
export function loadAllUsersStationsFromDB(username) {
return (dispatch, getState) => {
return new Promise((resolve, reject) => {
let linkTable = getStationsLinkTable(username); // get the local link table
if (linkTable && Array.isArray(linkTable.stations)) { // if there is a local station list
let loadPromises = linkTable.stations.map(stationID => dispatch(loadStationFromDB(stationID)).catch((err) => err));
Promise.all(loadPromises)
.then((allReasons) => {
let allSuccesses = true;
allReasons.forEach(reason => {
if (!reason.startsWith(SUCCESS_RESPONSE)) {
allSuccesses = false;
}
});
if (allSuccesses) {
resolve(SUCCESS_RESPONSE + ": " + username);
} else {
reject(allReasons);
}
})
} else {
return reject(NO_LINK_TABLE_AVAILABLE + ": " + username);
}
});
};
}
loadStationFromDB and loadLinkTableFromDB do what you'd expect... try to load those things from from the DB. I can include their code if you think it's worthwhile.
----------- EDIT -----------
To clarify what I'm trying to accomplish:
I'm trying to sync local storage with a database. I want to do this by pulling the data from the database, compare the time/datestamps. This will make the local storage version the authoritative copy of all the data. After the loads from the DB, I'd like to then push the local storage version up to the DB.
I need to care for the fact that the database will often simply not have the data at all, and thus might 'reject' on a pull... even though, in the instance of a sync, that rejection is acceptable and should not stop the sync process.
Per suggestions below, I've modified my code:
export function loadLinkTableAndElementsFromDB(tableType, username) {
console.log("loadLinkTableAndElementsFromDB(", tableType, username, ")");
return (dispatch, getState) => {
return new Promise((resolve, reject) => {
dispatch(loadLinkTableFromDB(tableType, username))
.then(successMsg => {
console.log("loadLinkTableFromDB RESOLVED: ", successMsg)
resolve(Promise.all([successMsg, dispatch(loadAllUsersStationsFromDB(username)).catch(err => err)]))
})
.catch(err => {
console.log("loadLinkTableFromDB REJECTED: ", err)
reject(Promise.all([err, dispatch(loadAllUsersStationsFromDB(username)).catch(err => err)]))
})
});
}
}
export function syncLinkTablesAndElementsWithDB(username) {
console.log("syncLinkTablesAndElementsWithDB(", username, ")");
return (dispatch, getState) => {
dispatch(loadLinkTableFromDB(STATIONS_LINK_TABLE_TYPE, username))
.then((successLoadLinkTableMsg) => {
console.log('Successfully loaded link table: ', successLoadLinkTableMsg)
return dispatch(pushLinkTableToDB(STATIONS_LINK_TABLE_TYPE, username))
})
.catch((rejectLoadLinkTableReason) => {
console.log("Failed to load link table from DB: " + rejectLoadLinkTableReason);
if (allReasonsAcceptableForOverwrite(rejectLoadLinkTableReason)) { // some rejection reasons are accectable... so if failed reason is okay....
console.log("Failure to load link table reasons were acceptable... pushing local link table anyway");
return dispatch(pushLinkTableToDB(STATIONS_LINK_TABLE_TYPE, username))
} else {
console.log("Throwing: ", rejectLoadLinkTableReason);
throw rejectLoadLinkTableReason;
}
})
.then((successPushLinkTaleMsg) => {
console.log("Successfully pushed link table: " + successPushLinkTaleMsg);
return dispatch(loadAllUsersStationsFromDB(username)); // I want this to occur regardless of if the link table stuff succeeds or fails... but it must occur AFTER the loadLinkTableFromDB at least tries...
})
.catch((rejectPushLinkTableReason) => {
console.log("Failed to push link table: " + rejectPushLinkTableReason);
return dispatch(loadAllUsersStationsFromDB(username)); // I want this to occur regardless of if the link table stuff succeeds or fails... but it must occur AFTER the loadLinkTableFromDB at least tries...
})
.then((successLoadAllUserStationsMsg) => {
console.log("Successfully loaded all user stations: " + successLoadAllUserStationsMsg);
return dispatch(pushAllUserStationsToDB(username))
})
.catch((rejectLoadAllUserStationsReason) => {
console.log("Failed to push all users stations: " + rejectLoadAllUserStationsReason);
if (allReasonsAcceptableForOverwrite(rejectLoadAllUserStationsReason)) { // some rejection reasons are accectable... so if failed reason is okay....
console.log("Load users stations reasons are acceptable...");
return dispatch(pushAllUserStationsToDB(username))
} else {
console.log("throwing: ", rejectLoadAllUserStationsReason);
throw rejectLoadAllUserStationsReason;
}
})
.then((successPushAllUserStationsMgs) => {
console.log("Successfully pushed all users stations: " + successPushAllUserStationsMgs);
return Promise.resolve();
})
.catch((rejectPushAllUserStationsReason) => {
console.log("Failed to push all users stations: " + rejectPushAllUserStationsReason);
throw rejectPushAllUserStationsReason;
})
};
}
export function syncAllWithDB(username) {
return (dispatch, getState) => {
// other stuff will occur here...
dispatch(syncLinkTablesAndElementsWithDB(username)) // *** Error here ***
.then((successMsg) => {
console.log("Successful sync for : " + successMsg);
})
.catch(allReasons => {
console.warn("Link tables and elements sync error: ", allReasons);
})
// });
}
}
Unfortunately, I'm now getting getting 'TypeError: dispatch(...) is undefined' on the dispatch in the syncAllWithDB function. This function hasn't changed...
I don't entirely follow what you're trying to accomplish (more on that below), but the first thing to do here is to clean up the flow and not wrap an extra new Promise() around existing promises. There is never a reason to do this:
function someFunc() {
return new Promise((resolve, reject) => {
callSomething.then(result => {
...
doSomethingElse(result).then(result2 => {
...
resolve(result2);
}).catch(err => {
...
reject(err);
});
}).catch(err => {
...
reject(err);
});
});
}
That is a well-known promise anti-pattern. You don't need the extra manually created promise wrapped around your function that already makes a promise. Instead, you can just return the promise you already have. This is called "promise chaining". From within the chain you can reject or resolve the chain from anywhere.
function someFunc() {
return callSomething.then(result => {
...
// return promise here, chaining this new async operation
// to the previous promise
return doSomethingElse(result).then(result2 => {
...
return result2;
}).catch(err => {
...
// after doing some processing on the error, rethrow
// to keep the promise chain rejected
throw err;
});
}).catch(err => {
...
reject err;
});
}
Or, you can even flatten the promise chain like this:
function someFunc() {
return callSomething.then(result => {
...
return doSomethingElse(result);
}).then(result2 => {
...
return result2;
}).catch(err => {
...
throw err;
});
}
As an example of that, you can simplify syncLinkTablesAndElementsWithDB() like this:
export function syncLinkTablesAndElementsWithDB(username) {
return (dispatch, getState) => {
return dispatch(loadLinkTableAndElementsFromDB(STATIONS_LINK_TABLE_TYPE, username)).then((msg) => {
console.log("loadLinkTableAndElementsFromDB RESOLVED: ", msg);
dispatch(pushLinkTableToDB(STATIONS_LINK_TABLE_TYPE, username))
dispatch(pushAllUserStationsToDB(username))
// have msg be the resolved value of the promise chain
return(msg);
}).catch((allPromReasons) => {
console.log("loadLinkTableAndElementsFromDB REJECTED: ", allPromReasons);
let allReasonsAcceptable = allPromReasons.every(reason => {
return isAcceptableLoadFailureReasonToOverwrite(reason);
});
if (allReasonsAcceptable) {
//TODO: DO push of local to DB
// eventually return results of the push to DB...
} else {
// have promise stay rejected
throw allPromReasons;
}
});
}
}
As for the rest of your question, you're asking this:
So if the "loadList" async function succeeds... I want to run the "loadElements" async function. If the loadList function rejects... I STILL want to run the "loadElements" function (Which fires off multiple fetch requests - one for each element).
But, there are not functions in your code called loadList() and loadElements() so you lost me there so I'm not sure how to make a specific code suggestion.
Inside a .then() handler in a promise chain, you can do three things:
Return a value. That value becomes the resolved value of the promise chain.
Return a promise. That promise is attached to the promise chain and the whole promise chain (the top-most promise that a caller would be watching) will eventually resolve/reject when this promise you are returning resolves/rejects (or anything that is also chained onto it resolves/rejects).
Throw an exception. All .then() handlers are automatically watched for exceptions and if any exception is throw, then the promise chain is automatically rejected with the exception value set as the reject reason.
So, that gives you the ultimate flexibility to finish the promise chain with a value or an error or to link it to another promise (more asynchronous operations).

How to return to parent function in JavaScript [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I have the following function at the moment, and I want to return "aaa" to the parent function (getStream), this is the code I have atm:
module.exports.getStream = (figure) => {
plotly.plot(figure, imgOpts, function(err, stream) {
if (err) {
console.log(err);
return "error";
}
return "aaa";
});
};
Right now, however, it returns undefined. What's the best solution to solve that problem?
The problem is that getStream does not return anything (therefore its return value is undefined). You have to add return before plotly or just remove curly braces. Also you'll have to return a promise, because that third argument of plotly.plot method is a callback function (I guess).
module.exports.getStream = (figure) =>
new Promise((resolve, reject) => {
plotly.plot(figure, imgOpts, function(err, stream) {
if (err) {
console.log(err);
reject("error");
}
resolve("aaa");
});
})
and then somewhere in the app:
const foo = async () => {
try {
const result = await getStream(figure)
console.log(result) // 'aaa'
} catch (err) {
console.log(err) // 'error'
}
}

Categories