Value below evaluate just now error with console.log - javascript

can someone help me solve this problem. I dont understand why console log and value of it after evaluate different. As you can see this pic below key SeqNo in console.log has no value but it actually has it
This is my function in component in Angular will return array and will be parameter for other function has above console.log
async prepareDetailForSave(allModelSalesTargetDetail) {
const salesTargetDetailForSave: any = [];
for (const detail of allModelSalesTargetDetail) {
await new Promise ((resolve, reject) => {
if (detail.SeqNo === '') {
if (detail.Money !== 0) {
detail.RSeqNo = this.objMaster.SeqNo;
detail.CreateDate = UtilsService.getCurrentDate();
detail.ModifiedDate = UtilsService.getCurrentDate();
if (this.global.connectionStatus === 'offline') {
detail.SeqNo = UtilsService.getLocalSeqno().toString();
} else {
this.jamService.getInvoiceCode('sales-target-detail').subscribe((res: any) => {
detail.SeqNo = res['seqno'];
});
}
salesTargetDetailForSave.push(detail);
}
} else {
salesTargetDetailForSave.push(detail);
}
resolve();
});
}
return salesTargetDetailForSave;
}

Related

JS then() not waiting for func result

export const getLocalStorageItem = (key, defaultValue = null) => {
const user = loadedStore.getState().session.user;
makeRequest(`/account/${user.id}/localstorage`, 'get').then((response) => {
try {
if (_.isNull(response.json.localstorage)) {
return defaultValue;
}
const formattedKey = `${key}_${user.id}`;
debugger
return response.json.localstorage[formattedKey] ? JSON.parse(response.json.localstorage[formattedKey].replaceAll("'", '"')) : defaultValue;
} catch (err) {
console.log(err); //eslint-disable-line-no-console } }); }
getColumns() {
const {
permissions
} = this.props;
let columns = [];
columns = getPartnerColumns(permissions);
const columnOptions = getPartnerColumns(permissions);
const tableViewOptions = [];
if (permissions === 'admin') {
const localStorageColumns = getLocalStorageItem(this.localStorageColumnConfigurationKey);
debugger // If the user has a saved column list, use it. if (localStorageColumns) { columns = [ ...localStorageColumns.map((c) => { const options = columnOptions.find((opt) => opt.id === c); return options; }) ]; } }
Why isn't the return value from the function seen in the first code presented being saved in the variable const localStorageColumns?
How can I wait for the fund's result?
I think that the request isn't fullfiled by the time the function returns, specially because the 1st debugger point is the one after the function and only then the one inside the function.
Promises are asynchronous in javaScript, which means that the result of a promise is available "later" or more exactly as soon as the asynchronous instructions finish, and javascript continues to execute the rest of the instructions while the async stuffs are being executed in the background.
If you want javascript to wait for a promise to either resolve and reject, you should use async/await as show in the snippet bellow.
Please find more on promise here https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Promises
export const getLocalStorageItem = async (key, defaultValue = null) => {
const user = loadedStore.getState().session.user;
const item = await makeRequest(`/account/${user.id}/localstorage`, 'get').then(
(response) => {
try {
if (_.isNull(response.json.localstorage)) { return defaultValue; }
const formattedKey = `${key}_${user.id}`;
return response.json.localstorage[formattedKey] ?
JSON.parse(response.json.localstorage[formattedKey].replaceAll("'", '"')) :
defaultValue;
} catch (err) {
console.log(err);
}
});
return item ?? defaultValue;
}

Undefined reading in promise chain

I have a simple employee profile generator app. Everything works just as expected up until the promise for generatePage(employeeData). The console correctly logs employeeData but it is not getting passed to generatePage. Does anyone have insight into why? I have also included a picture of the beginning code for generate-page.js and the "undefined" console error message.
const {writeFile, copyFile} = require('./utils/generate-site.js');
const generatePage = require('./src/page-template.js');
const mockData = [
{
// lots of mock data objects here
},
]
let employeeData = mockData;
function init() {
return inquirer.prompt(questions.startQuestions);
}
function getEmployeeData(answers) {
if (answers.role === 'Engineer') {
let engineer = new Engineer (
answers.name,
answers.id,
answers.email,
answers.role
)
return getEngineerData(engineer);
} else if (answers.role === 'Intern') {
let intern = new Intern (
answers.name,
answers.id,
answers.email,
answers.role
)
return getInternData(intern)
} else if (answers.role === 'Manager') {
let manager = new Manager (
answers.name,
answers.id,
answers.email,
answers.role
)
return getManagerData(manager)
}
}
function getEngineerData(engineer) {
return new Promise((resolve) => {
resolve (
inquirer.prompt(questions.engineerQuestions)
.then ((response) => {
engineer = {...engineer, ...response};
// console.log(engineer)
employeeData.push(engineer)
}
)
)
})
}
function getInternData(intern) {
return new Promise((resolve) => {
// same as getEngineerData function
})
}
function getManagerData(manager) {
return new Promise((resolve) => {
// same as getEngineerData function
})
}
function confirm() {
return inquirer.prompt(questions.confirmQuestion)
}
function buildTeam() {
init()
.then(answers => getEmployeeData(answers))
.then(confirm)
.then(response => response.confirmAdd ? buildTeam() : console.log(employeeData))
.then(employeeData => generatePage(employeeData))
.then(pageHTML => {
return writeFile(pageHTML)
})
.then (writeFileResponse => {
console.log(writeFileResponse);
return copyFile()
})
.then(copyFileResponse => {
console.log(copyFileResponse);
})
.catch (err => {
console.log(err);
});
}
buildTeam();
console.log returns "undefined" so the solution was to return the employeeData array in the promise chain to pass on.
.then(response => {
if (response.confirmAdd) {
buildTeam()
return employeeData
} else {
return employeeData
}
})

How to implement a simpler Promise in JavaScript?

I'm learning JavaScript, and I decided that an excelent chalenge would be to implement a custom Promise class in JavaScript. I managed to implement the method then, and it works just fine, but I'm having difficulties with the error handling and the method catch. Here is my code for the Promise class (in a module called Promise.mjs):
export default class _Promise {
constructor(executor) {
if (executor && executor instanceof Function) {
try {
executor(this.resolve.bind(this), this.reject.bind(this));
} catch (error) {
this.reject(error);
}
}
}
resolve() {
if (this.callback && this.callback instanceof Function) {
return this.callback(...arguments);
}
}
reject(error) {
if (this.errorCallback && this.errorCallback instanceof Function) {
return this.errorCallback(error);
} else {
throw `Unhandled Promise Rejection\n\tError: ${error}`;
}
}
then(callback) {
this.callback = callback;
return this;
}
catch(errorCallback) {
this.errorCallback = errorCallback;
return this;
}
}
When I import and use this class in the following code, all the then() clauses run as according, and I get the desired result in the console:
import _Promise from "./Promise.mjs";
function sum(...args) {
let total = 0;
return new _Promise(function (resolve, reject) {
setTimeout(function () {
for (const arg of args) {
if (typeof arg !== 'number') {
reject(`Invalid argument: ${arg}`);
}
total += arg;
}
resolve(total);
}, 500);
});
}
console.time('codeExecution');
sum(1, 3, 5).then(function (a) {
console.log(a);
return sum(2, 4).then(function (b) {
console.log(b);
return sum(a, b).then(function (result) {
console.log(result);
console.timeEnd('codeExecution');
});
});
}).catch(function (error) {
console.log(error);
});
But, when I add an invalid argument to the sum() function, i.e. not a number, the reject() method runs, but it don't stop the then() chain, as should be, and we also get an exception. This can be seen from the following code:
import _Promise from "./Promise.mjs";
function sum(...args) {
let total = 0;
return new _Promise(function (resolve, reject) {
setTimeout(function () {
for (const arg of args) {
if (typeof arg !== 'number') {
reject(`Invalid argument: ${arg}`);
}
total += arg;
}
resolve(total);
}, 500);
});
}
console.time('codeExecution');
sum(1, 3, '5').then(function (a) {
console.log(a);
return sum(2, 4).then(function (b) {
console.log(b);
return sum(a, b).then(function (result) {
console.log(result);
console.timeEnd('codeExecution');
});
});
}).catch(function (error) {
console.log(error);
});
Also, if I catch an error in nested then() methods, the outer catch() doesn't notice this and I get an exception again. The goal is to implement a lightweight functional version of Promises, but not necessarily with all its functionality. Could you help me?
The problem in your code is that your sum function calls both the reject and the resolve functions. There's no handling in the sum function that will cause it not to call the resolve function at the end, and there is nothing in your _Promise that blocks this behavior.
You have 2 options to fix this.
Option 1 would be if you want your _Promise to act like a real Promise you will need to manage a state and once a promise got to a final state stop calling the callback or errorCallback.
Option 2 would be to prevent from calling both reject and resolve in the function calling the _Promise, in this case, the sum function.
With the comments that you guys provide me, I was able to improve the code and correct the errors mentioned, as shown below. Now, I would like you to give me suggestions on how to proceed and improve the code. Thanks. (The code can also be found on github).
const PENDING = 0;
const FULFILLED = 1;
const REJECTED = 2;
function _Promise(executor) {
let state = PENDING;
let callOnFulfilled = [];
let callOnRejected = undefined;;
function resolve(...args) {
if (!state) {
state = FULFILLED;
}
resolveCallbacks(...args);
};
function reject(error) {
state = REJECTED;
if (callOnRejected && (callOnRejected instanceof Function)) {
callOnRejected(error);
callOnRejected = undefined;
callOnFulfilled = [];
} else {
throw `Unhandled Promise Rejection\n\tError: ${error}`;
}
};
function resolveCallbacks(...value) {
if (state !== REJECTED) {
let callback = undefined;
do {
callback = callOnFulfilled.shift();
if (callback && (callback instanceof Function)) {
const result = callback(...value);
if (result instanceof _Promise) {
result.then(resolveCallbacks, reject);
return;
} else {
value = [result];
}
}
} while (callback);
}
};
if (executor && (executor instanceof Function)) {
executor(resolve, reject);
}
this.then = function (onFulfilled, onRejected) {
if (onFulfilled) {
callOnFulfilled.push(onFulfilled);
if (state === FULFILLED) {
resolveCallbacks();
}
}
if (onRejected && !callOnRejected) {
callOnRejected = onRejected;
}
return this;
};
this.catch = function (onRejected) {
return this.then(undefined, onRejected);
};
}
function sum(...args) {
let total = 0;
return new _Promise(function (resolve, reject) {
setTimeout(function () {
for (const arg of args) {
if (typeof arg !== 'number') {
reject(`Invalid argument: ${arg}`);
}
total += arg;
}
resolve(total);
}, 500);
});
}
console.time('codeExecution');
sum(1, 3, 5).then(function (a) {
console.log(a);
return sum(2, 4).then(function (b) {
console.log(b);
return sum(a, b).then(function (result) {
console.log(result);
return 25;
});
}).then(function (value) {
console.log(value);
console.timeEnd('codeExecution');
});
}).catch(function (error) {
console.log(error);
});

How to properly format nested try/catch blocks inside a function that returns a server response

I have a function that is called that must return a response to a server. Inside this function are two await function calls that are nested. To track error handling, I added try/catch blocks. Is there a way to avoid having nested try catch blocks to track all cases where the function might fail so I can send back an error server response?
Here's my function, it queries for a user's unique device id's and sends a push notification to each one. If a token becomes invalid, then I delete it from my database:
function findUserDevices(uid: string, message) {
collectionData(fb.firestore().collection('devices').where('userId', '==', uid)).pipe(
filter((userDevices) => userDevices && userDevices.length > 0),
take(1)
).subscribe( async (devices: any) => {
var userDeviceTokens: string[] = devices.map((device: any) => device.token);
if (userDeviceTokens !== undefined && userDeviceTokens.length != 0) {
try {
message['tokens'] = userDeviceTokens;
const pushResponse = await admin.messsaging().sendMulticast(message);
if (pushResponse.failureCount > 0) {
const failedTokens = [];
pushResponse.responses.forEach((resp, idx) => {
if (!resp.success) {
failedTokens.push(userDeviceTokens[idx]);
}
});
failedTokens.forEach( async (token) => {
var tokenInstanceID = token.split(':')[0];
try {
await deleteOldToken(tokenInstanceID);
console.log(`Token ${tokenInstanceID} deleted`)
} catch {
return res.status(500).send("err");
}
})
return res.status(200).send("ok");
} else {
return res.status(200).send("ok");
}
} catch {
return res.status(500).send("err");
}
} else {
return res.status(200).send("ok");
}
})
}
It just feels a bit excessive with all the returns I must have. Where can I improve?
EDIT, broke apart code into three blocks to prevent arrow coding
function findUserDevices(uid: string, message) {
collectionData(fb.firestore().collection('devices').where('userId', '==', uid)).pipe(
filter((userDevices) => userDevices && userDevices.length > 0),
take(1)
).subscribe(async (devices: any) => {
var userDeviceTokens: string[] = devices.map((device: any) => device.token);
if (userDeviceTokens !== undefined && userDeviceTokens.length != 0) {
try {
message['tokens'] = userDeviceTokens;
const response = await admin.messaging().sendMulticast(message);
const oldTokensArray = checkOldTokens(response, userDeviceTokens);
if (oldTokensArray.length > 0) {
await deleteOldTokens(oldTokensArray);
return res.status(200).send("ok");
} else {
return res.status(200).send("ok");
}
} catch (err) {
return res.status(500).send(err);
}
} else {
return res.status(200).send("ok");
}
})
}
function checkOldTokens(response, userDeviceTokens) {
if (response.failureCount > 0) {
const failedTokens = [];
response.responses.forEach((resp, idx) => {
if (!resp.success) {
failedTokens.push(userDeviceTokens[idx]);
}
});
return failedTokens;
} else {
return [];
}
}
async function deleteOldTokens(tokenArray) {
for (const token of tokenArray) {
await fb.firestore().collection('devices').doc(token).delete();
}
}

Calling a promise function recursively

I'm trying to call a promise function recursively.
The following call service.getSentenceFragment() returns upto 5 letters from a sentence i.e. 'hello' from 'helloworld. Providing a nextToken value as a parameter to the call returns the next 5 letters in the sequence. i.e. 'world'. The following code returns 'hellohelloworldworld' and does not log to the console.
var sentence = '';
getSentence().then(function (data)) {
console.log(sentence);
});
function getSentence(nextToken) {
return new Promise((resolve, reject) => {
getSentenceFragment(nextToken).then(function(data) {
sentence += data.fragment;
if (data.nextToken != null && data.nextToken != 'undefined') {
getSentence(data.NextToken);
} else {
resolve();
}
}).catch(function (reason) {
reject(reason);
});
});
}
function getSentenceFragment(nextToken) {
return new Promise((resolve, reject) => {
service.getSentenceFragment({ NextToken: nextToken }, function (error, data) {
if (data) {
if (data.length !== 0) {
resolve(data);
}
} else {
reject(error);
}
});
});
}
Cause when you do this:
getSentence(data.NextToken);
A new Promise chain is started, and thecurrent chain stays pending forever. So may do:
getSentence(data.NextToken).then(resolve, reject)
... but actually you could beautify the whole thing to:
async function getSentence(){
let sentence = "", token;
do {
const partial = await getSentenceFragment(token);
sentence += partial.fragment;
token = partial.NextToken;
} while(token)
return sentence;
}
And watch out for this trap in getSentenceFragment - if data is truthy but data.length is 0, your code reaches a dead end and the Promise will timeout
// from your original getSentenceFragment...
if (data) {
if (data.length !== 0) {
resolve(data);
}
/* implicit else: dead end */
// else { return undefined }
} else {
reject(error);
}
Instead, combine the two if statements using &&, now our Promise will always resolve or reject
// all fixed!
if (data && data.length > 0)
resolve(data);
else
reject(error);
You could recursively call a promise like so:
getSentence("what is your first token?")
.then(function (data) {
console.log(data);
});
function getSentence(nextToken) {
const recur = (nextToken,total) => //no return because there is no {} block so auto returns
getSentenceFragment(nextToken)
.then(
data => {
if (data.nextToken != null && data.nextToken != 'undefined') {
return recur(data.NextToken,total + data.fragment);
} else {
return total + data.fragment;
}
});//no catch, just let it go to the caller
return recur(nextToken,"");
}
function getSentenceFragment(nextToken) {
return new Promise((resolve, reject) => {
service.getSentenceFragment({ NextToken: nextToken }, function (error, data) {
if (data) {
if (data.length !== 0) {
resolve(data);
}
} else {
reject(error);
}
});
});
}

Categories

Resources