JavaScript | Access the object of a Promise from another Promise - javascript

In my AngularJS Application, I want to access the return value of a Promise, which I access from a service outside of my controller and import it there. This Promise, return an object. I want to access that objects and properties inside it.
I created the service to get that endpoint. Look below:
export const getEndpoints = () => {
const options = {
method: httpMethod.GET,
url: endpoint.ENVIRONMENT,
};
return Instance(options);
};
The above service in return reads an endpoint which I provide and uses axios on the background. This part is working just fine.
Then imported it, on my angular Controller:
import { getEndpoints } from './config/service';
Finally I created this function:
$scope.isItAvailable = false; // I will use this later to check the actual value. It is not important in the scope of the question..
const checkIfItIsAvailable = () => {
return new Promise((resolve, reject) => {
resolve(getEndpoints)
console.log(getEndpoints)
})
}
// And in my main function I am just calling the above
const mainFn = () => {
checkIfItIsAvailable()
// Along with a few others..
}
Actual Results
Now, in my console, I get the functioncheckIfItAvailable printed out.
Expected Results
I instead want to print to the console, the actual value that is being returned by the original promise, the object, and its properties.

Probably You need to call that function instead of just passing it as a parameter.
const checkIfItIsAvailable = () => {
return new Promise((resolve, reject) => {
resolve(getEndpoints()) // here
console.log(getEndpoints())
})
}
Then to get that resolved later in your main function, or wherever - just use then:
const mainFn = () => {
checkIfItIsAvailable().then((result) => {
// do what you need with result here
// $scope.isItAvailable = result probably like this
});
}
Please comment if you need another result. I see at least this issue at the moment.
Also, here is a snipper, illustrating that you need to call it instead of just passing.
// here is an example function which just return some string
function getSomething() {
return 'something'; // it could be a promise also
}
// here is example without calling functions, but just passing:
const promise = new Promise((resolve, reject) => {
console.log('NO CALL: ', getSomething);
});
// here is example with calling, so value is resolved
const promise2 = new Promise((resolve, reject) => {
console.log('CALLED: ', getSomething());
});

Here, getEndpoints is an asynchronous function which returns a Promise, and the way to get a return value from promise is to use then callback. You can do it like this:
const checkIfItIsAvailable = () => {
return new Promise((resolve, reject) => {
getEndpoints().then(resultOfEndPoint => {
console.log(resultOfEndPoint);
resolve(resultOfEndPoint);
});
})
}

It's possible to access the resolved result of getEndpoints in checkIfItIsAvailable calling getEndpoints() and using then() function:
const checkIfItIsAvailable = () => {
return new Promise((resolve, reject) => {
// call getEndpoints
getEndpoints()
// call then to get a result from getEndpoints
.then(res => {
console.log(res);
// checkIfItIsAvailable will be resolved with
// the result of getEndpoints
resolve(res);
});
});
}

Related

Promises jumping too fast to then() (vanilla JS)

I have a problem with promises. The point is that the one function isn't completed and the executing code is jumping to then method.
const load = (function() {
const site = function(url, parent) {
return fetch(url)
.then(response => {
return response.text()
})
.then(data => {
parent.innerHTML = data;
})
};
return {
site: site,
};
})();
function mainApp() {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log(document.querySelector('.content'));
const welcome = document.createElement('div');
const content = document.querySelector('.content');
welcome.textContent = `Welcome, ${user.displayName}`;
content.appendChild(welcome);
} else {
}
});
}
function promise() {
return new Promise((resolve, rejected) => {
load.site('pages/main/main.html', content);
//this function isn't completed and executing code is jumping to then
})
}
promise().then(() => {
console.log('then');
mainApp(); //this function is called before the upper code is completed
});
And because of this bug I can't change the DOM in mainApp function because this function is completed before the load function (which is also changing to DOM by using fetch). My goal is to firstly call and complete load.site() and then mainApp() but I don't know what's happening now and where is the problem.
I assume that you assumed that we assume that you resolved the function like
function promise() {
return new Promise((resolve, rejected) => {
load.site('pages/main/main.html', content);
resolve(); // Like this.
})
}
The Problem
When you call promise. It calls load.site and then resolves. So why isn't it giving the expected behavior.
Well, the problem is that load.site is a synchronous function, so it does not wait for the fetch call and returns which resolves promise before fetch is resolved. So, the code in promise.then() runs before the code in fetch.then()
The Solution
Make load.site an asynchronous function so that it returns a promise that can be awaited. i.e.
const site = async function (url) {
return fetch('a.js')
.then(response =>{
return response.text()
})
.then(data =>{
console.log("Loaded");
})
};
Then make the promise's executor async so that you await load.site. i.e.
function promise() {
return new Promise(async (resolve, rejected) => {
await load.site('pages/main/main.html'); // This line does the magic
resolve();
});
};
This will make sure that your promise resolves after fetch has resolved. So that you can get the expected behavior.
Hope it helps. Keep on coding

How do I access promise callback value outside of the function?

It is to my understanding that callback functions are asynchronous and cannot return a value like regular functions. Upon reading about promises, I thought I grasped a good understanding about them, that they are basically an enhanced version of callbacks that allows returning a value like asynchronous function. In my getConnections method, I am attempting to call the find() function on my database through mongoose, and I am attempting to grab this array of objects and send it to the views.
var test = new Promise((resolve, reject) => {
Database.find().then(list => {
resolve(list);
}).catch(err=> {
return reject(err);
})
})
console.log(test)
When I attempt to log to the console outside of the promise function, I get Promise { _U: 0, _V: 0, _W: null, _X: null }
I don't think this is functioning correctly, and I thought I utilized promises correctly. Could anyone point me in the right direction on how to return this array of objects outside of the callback function?
You can simply add await before the promise declaration.
i.e.
var test = await new Promise...
The thing is that when you write a function like this:
const getData = async () => { const response = await fetch(someUrl, {}, {}); return response;}
Then you also need to await that function when you call it. Like this:
const setData = async () => { const dataToSet = await getData(); }
let test = new Promise((resolve, reject) => {
Database.find().then(list => {
resolve(list);
}).catch(err=> {
return reject(err);
})
})
test
.then(result=>console.log(result))
Should solve your problem.
var someValue;
var test = await new Promise((resolve, reject) => {
Database.find().then(list => {
resolve(list);
}).catch(err=> {
return reject(err);
})
}).then(res => {
someValue=res;
})
console.log(someValue);

How to resolve the second promise if it required the first promise resolved result's element?

I have 2 function getAccountInfo() and getAdjustmentsInfo(accountInfo) they both return a new promise. The only different is that the second function needs the information returned from the first function.
I tried to declare these 2 function first, and call them one by one using then(). It worked but the problem is, the second fuction needs the the result from the first promise.
Not only that, the first promise returned an array, for example an array of 10 accounts infomation. But the second function only needs the attribute of the account information, for example account_code.
So I think I need to run the second function 10 time..? I am not very sure how to do that.
These are the functions, as you can see the second function needs account_code from the first accountInfo object:
function getAccountInfo() {
return new Promise((resolve, reject) => {
getAccountCallbackFunc((errResponse, response) => {
if (errResponse) {
return reject(errResponse);
}
resolve(response);
});
});
}
function getAdjustmentsInfo(accountInfo) {
return new Promise((resolve, reject) => {
getAdjustmentCallbackFunc(accountInfo[0].account_code, function (errResponse, response) {
if (errResponse) {
reject(errResponse);
}
if (response) {
resolve(response);
}
});
});
}
This is the controller code to call the functions:
var accountInfo = {};
var adjustmentsInfo = {};
getAccountInfo()
.then(response => {
accountInfo = response.data.accounts.account;
getAdjustmentsInfo(accountInfo)
})
.then(response => {
adjustmentsInfo = response.data.adjustments;
})
.catch(err => console.log(err));
I changed the second function into somthing like this, below is the code I changed to, so it can loop:
function getAdjustmentsInfo(accountInfo) {
return new Promise((resolve, reject) => {
let result = {};
for(account of accountInfo){
getAdjustmentCallbackFunc(account.account_code, function (errResponse, response) {
if (errResponse) {
reject(errResponse);
}
if (response) {
result += response;
}
});
}
console.log(result);
resolve(result);
});
}
So I run the getAccountInfo() function first and run the first then() to saved the account information to the external variable accountInfo.
Next I run the second then() trying to pass the accountInfo to the second function, second function will loop and run the inner getAdjustmentCallbackFunc() multiple times to create and new result and resolve it. I dont't know why it is not working. Is that something I am missing? Please let me know.
getAccountInfo()
.then(info => {
return Promise.all(info.accounts.map(a => getAdjustmentsInfo(a)));
})
.then(adjustments => {
// array of 10 adjustments
})

Vue exports.function syntax

i have a function like this in a separate file.
exports.getScore = (storeId) => {
var getScore = new Promise(function (resolve, reject) {
let data = this.getScore('day', storeId)
data.then(function (result) {
resolve(result)
})
})
let result
await getScore.then(function (data) {
result = data
})
return result
}
Can anyone help me with the syntax so i can make async runs, and then execute my await call?
Thanks in advance.
For your question you just need to place an async before your function
exports.getScore = async (storeId) => { /* snip */ }
But actually there are some problem in your code
First, you can pass a promise in Promise executor's resolve
new Promise(resolve => {
// This will work
resolve(anotherPromise)
})
However, if you already have a promise you can just return it directly
If you want to make sure it's a native Promise or you are not sure that it's a Promise or not.
Wrap it in Promise.resolve
Promise.resolve(anotherPromiseOrValue)
So your code can change into:
exports.getScore = (storeId) => this.getScore('day', storeId)
And it also equal:
exports.getScore = this.getScore.bind(this, 'day')
But there is another problem: what is the this here ?
If you extract this function from Vue methods, then the this probably is a Vue instance.
Then I afraid that the above code wont work as you expected.
So I recommend that you just use getScore in your component's lifecycle hook, like mounted
For example:
mounted () {
this.getScore('day', this.storeId).then(score => {
this.score = score
})
}
Or with async/await
async mounted () {
this.score = await this.getScore('day', this.storeId)
}

How to flatten a Promise within a Promise?

I have the following 2 functions, each returns a Promise:
const getToken = () => {
return new Promise((resolve, reject) => {
fs.readFile('token.txt', (err, data) => {
if (err) { return reject(err) }
if (!tokenIsExpired(data.token)) {
return resolve(data.token)
} else {
return requestNewToken()
}
})
})
}
const requestNewToken = () => {
return new Promise((resolve, reject) => {
restClient.get(url, (data, res) => {
fs.writeFile('tokenfile.txt', data.token, err => {
resolve(data.token)
})
})
})
}
function1()
.then(value => {
console.log('taco')
})
.catch(err => {
console.log(err)
})
So function1 runs, and (depending on some condition), it sometimes returns function2, which is returning another Promise. In this code, when function2 is called, the console.log('taco') never runs. Why is this? I thought that if you return a Promise from within a Promise, the resolved value of the nested Promise is what is resolved at the top level.
In order for me to get this to work, I have to do this:
const getToken = () => {
return new Promise((resolve, reject) => {
if (!tokenIsExpired()) {
return resolve(getToken())
} else {
return requestNewToken ()
.then(value => {
resolve(value)
})
}
})
}
That works, but it seems like I'm doing something wrong. It seems like there should be a more elegant way to handle/structure this.
You're right that promises auto-unwrap, but in this case you're returning from inside a promise constructor, which is ignored, you need to invoke either resolve or reject instead of using return. I think this might be the solution you're looking for:
const function1 = () => {
return new Promise((resolve, reject) => {
if (someCondition) {
resolve('foobar')
} else {
resolve(function2());
}
})
}
Inside a promise constructor, you need to call resolve or reject, which are equivalent to using return or throw from inside a then callback.
If you find this distinction confusing (I do), you should avoid the promise constructor entirely by just beginning a new chain with Promise.resolve, like this:
const function1 = () => {
return Promise.resolve().then(() => {
if (someCondition) {
return 'foobar';
} else {
return function2();
}
})
}
const function2 = () => {
return new Promise((resolve, reject) => {
resolve('hello world')
})
}
someCondition = false;
function1()
.then(value => {
console.log(value)
})
With your updated code, I recommend using a library to wrap APIs, rather than accessing the promise constructor yourself. For example, using bluebird's promisify:
const bluebird = require('bluebird');
const readFile = bluebird.promisify(fs.readFile);
const writeFile = bluebird.promisify(fs.writeFile);
const getUrl = bluebird.promisify(restClient.get, {multiArgs:true});
const getToken = () => {
return readFile('token.txt')
.then((data) => {
if(!tokenIsExpired(data.token)) {
return data.token;
} else {
return requestNewToken();
}
});
};
const requestNewToken = () => {
return getUrl(url)
.then(([data, res]) => {
return writeFile('tokenFile.txt', data.token)
.then(() => data.token);
});
};
I've remained faithful to your source code, but I'll note there may be a bug to do with writing data.token, and later trying to read the token property in that file.
Why use a library instead of the Promise constructor?
It allows you to write code which deals only with promises, which is (hopefully) easier to understand
You can be confident that callback APIs are correctly converted without losing errors. For example, if your tokenIsExpired function throws an error, using your promise constructor code, it would be lost. You would need to wrap all of your inner callback code in try {} catch(e) {reject(e)}, which is a hassle and easily forgotten.

Categories

Resources