Promise troubles with pnp/sp - javascript

I am building an application customiser in SPFX and I am using pnp/sp to get data from a Sharepoint list - all easy so far. I have figured out the code like this, but it is just returning [object promise] here is my code , any help would be brilliant.
I am calling the function like this :
public emailAddressGetter = this.GetSharePointData();
I am trying to show the output like this :
${escape(this.emailAddressGetter.toString())}
and this is the promise I am executing :
private async GetSharePointData(): Promise<any>
{
let myVar : string;
var resultData: any = await sp.web.lists
.getByTitle('Emails')
.items
.select('EmailAddress')
.getById(99)
.get().then((r => {
myVar = r.EmailAddress;
}));
console.log(myVar);
return myVar;
}
any help would be appreciated, I know I am almost there :) thanks guys

I think your GetSharePointData returns a Promise, because it has async declaration, so you need to execute code asynchronously and wait for the result.
Instead of:
public emailAddressGetter = this.GetSharePointData();
${escape(this.emailAddressGetter.toString())}
Try:
this.GetSharePointData()
.then(res => {
// res here is myVar
${escape(res.toString())};
});

Firstly fix your code's type annotations. You are completely defeating the point of TypeScript by suppressing the errors the language exists to catch by specifying vacuous types instead of leveraging inference. This isn't Java.
async GetSharePointData() { // return type is inferred as `Promise<string>`
const result = await sp.web.lists // the `any` you had here was worse than useless.
.getByTitle('Emails')
.items
.select('EmailAddress')
.getById(99)
.get();
const emailAddress= result.emailAddress;
console.log(emailAddress);
return emailAddress;
}
Now onto async functions and promises. An async function or method always returns a promise. Assigning the result of calling such a function directly to a property or variable will always result in the behavior you described
GetSharePointData().toString() === "[object Promise]"
The correct approach to setting the property emailAddressGetter (BTW that's a terrible name for that property either way) to the email address that the promise eventually resolves with depends on the context, but here is something you might do.
constructor() {
this.emailAddressPromise = this.GetSharePointData();
this.emailAddressPromise.then(emailAddress => this.emailAddress = emailAddress);
}
But that could be awful and unnecessary unpredictable depending on what you are trying to do.

Related

CefSharp Javascript Callback never return resolved promise

First of all, excuse my English, it's very bad. I am using CefSharp in WinForms app for comunication between navigator and .NET code.
I'm trying to resolve a promise in an asynchronous callback function with CefSharp, but in the response returned to .Net I never get the response of the resolved promise, but rather an object that seems to represent the consumers of said promise (finally, catch, then).
Is there any way to solve this?
I leave an example that I hope can help you in understanding the problem.
//C# code
public void TestCallback(IJavascriptCallback javascriptCallback)
{
const int taskDelay = 1500;
Task.Run(async () =>
{
await Task.Delay(taskDelay);
using (javascriptCallback)
{
var result = await javascriptCallback.ExecuteAsync();
//result is a JavaScriptResponse, but property "Result" is not "user" object, is a dictionary object with 'then', 'catch', 'finally' keys.
}
});
}
//JS code
function async MyCallback()
{
// read our JSON
let response = await fetch('/article/promise-chaining/user.json');
let user = await response.json();
return user;
}
boundAsync.testCallback(MyCallback);
Thank you very much.
Regards
Borja
This has been solved now, in version 88 of cefsharp:
https://github.com/cefsharp/CefSharp/wiki/Advanced-Async-JavaScript-Binding-(JSB)/07c45fa962174d0476c4f2206f707365e9b11edd#javascript-callback-with-promise

data type of value returned from Promise or async / await

i know there's a bunch of related questions / posts regarding this question but they don't really answer my question, my question here is simple, if I have a promise and i wrapped it in an async function and await it til it's settled like this:
async function getUserData() {
return fetch('url'); // fetch returns a promise, wrapping the user data returned
}
async main() {
const user = await getUserData();
// what is the type of the user object here?
}
I'm asking this question because I'm using TypeScript, I usually try to type cast the return value to the expected type like this:
async function getUserData() {
return fetch('url') as UserInfo;
}
say UserInfo has a name attribute but if I try write in this way then user.name is undefined:
async function main() {
const user = await getUserData();
console.log(user.name); // undefined.
}
it makes me how should I 'unwrap' a promise with a value in it?
You can't really know at compile time what it is, because this is explicitly something that happens at runtime.
So usually the result of a JSON.parse() is any. A stricter version could be the unknown type.
If you want to just assume whatever you got back is going to be the right type, without validating (because you trust the server), I think I would do that as such:
async function getUserData(): Promise<UserInfo> {
return fetch('url'); // fetch returns a promise, wrapping the user data returned
}
I could be wrong, but I think the way that Async/Await works is that it wraps the function in a native promise.
I tested out your examples in the browser console and both functions return a Promise.
Promise {<pending>}
I am not sure about what that is cast to in Typescript as I don't use it. But if you drop into the browser console you can test all of this. It functions as a pretty good REPL.
As a function of design, the getUserData() function does not need to be async as you are not awaiting anything in it.
As for unwrapping it, you can use the fetch API since you now have a fetch result:
const data = getUserData();
data.then(response => response.json())

Trouble with axios returning promise object

I imagine it's something really simple, but I'm having some trouble getting the correct response. My code is returning the promise object, and not the value.
My axios call is something like this:
export const myFunc = async (hash: string) => {
return axios.get(`${url}/${path}?hash=hash`)
.then((response: any) => {
console.log('my response: ', response.data) // {key: value} as expected
return response.data
})
}
I call it from another file
const xy = async (c: string) => {
return myFunc(c)
}
console.log('result of xy(): ' xy('some hash')) // result of xy(): { Promise <pending> } <--- ????
If I .toString() it, because I'm annoyed (and I think I had some reason why at one point but I don't remember what that is), I get
result of xy(): [object Promise]
I've googled, I've stack overflowed, and now I'm asking the question because what I've found so far doesn't quite work.
Thanks for you help
Explicit promise syntax fixed the issue. I'm sure I was missing something really simple. Thanks much to #EmileBergeron. But we also decided that the data didn't need to be encrypted at rest, so by storing this non sensitive data in an unencrypted state, we no longer needed to make a separate rest call to un-encrypt the hash and didn't need to worry about working in an additional promise in the first place.

Unexpected Promise in React Native

I am new to React Native and coding in general. I paid for some code on upwork and am having a hard time integrating it in my program.
async pullBatch(since){
let param = {
userScreenName: '?screen_name=google',
count: "&count=5",
retweets: "&include_rts=false",
replies: "&exclude_replies=false",
trim: "&trim_user=true",
since: "&max_id=" + since
};
let twitterRest = new TwitterRest(); //create a new instance of TwitterRest Class
let batch = await twitterRest.pullTweets(param); //pull the Google TimeLine
return batch;
}
pullTimeline(){
let timeLine = []
for(i = 0; i <= 2; i++){
let currentBatch = this.pullBatch("1098740934588751900")
console.log(currentBatch);
timeLine = timeLine.concat(currentBatch);
}
console.log(timeLine);
// timeLine = currentBatch
return(timeLine)
}
I believe that when running pullTimeLine() the program is returning an array of three promises. (I have also run the code with "await" before pullBatch(), but it is erroring out telling me await is a reserved word) This means I am making two mistakes:
I am not correctly understanding promises in JS or how they are resolved.
I am incorrectly concatenating the arrays.
I am constantly trying to learn, so while I greatly appreciate suggestions for code fixes, I also really would appreciate if you'd teach me about where my lapses in understanding lies.
Thank you
Let's break it down. You seem to understand that pullBatch is an async function, and so calling it will return a promise create by the twitterRest interaction.
The problem is that your call to pullBatch inside your for loop will not resolve these promise (which seems to be what you want to do). The easiest way is to use await for currentBatch, but as you tried, you got the reserved error. Basically you just need to also make pullTimeline async like this:
async pullTimeline(){
...
Just realise that once you do this, pullTimeline is now an async function that will also return a promise. So to use this function you need to either use .then(), for example:
pullTimeline().then(timeLine => {
// do something with your timeline here
})
Or if you are using it within another async function, you can use await.
const timeLine = await pullTimeline() // must be inside async function
Basically at some point in your calling chain, you will have to resolve a promise using .then(), or disregard the top level promise by making a top level async function. For example:
async useTimeline() {
const timeLine = await pullTimeline()
// do something with your timeline
}
// call the function above, and just disregard its promise
useTimeLine()
Just don't forget to handle errors somewhere. Either use a .catch() on your top level promise, or use try / catch around any of your await calls.

Knex.js non-terminating functions

I don't have any problem in this question, I am just interested in how knex.js menaged to something.
In code, you can write something like this
let search = knex.table('users').select('something')
if(params.minprice) search.where('minprice', params.minprice)
if(something) search.something()
let result = await search
It works, but I don't get how did they menage to hold query execution until await occured? If we did await, it means function was async aka returned a promise. But in javascript, promise executes as soon as function that returned it is called, it does not care is there .then() or .catch(). Should not query execution start al line 1? What is more, when I log search, it is not a promise, but some kind of object, so how can it be awaited?
Can someone provide a simple example how to achieve such a behaviour?
I'm guessing that search contains a property named then, which is a function that initiates the search and also behaves similarly to the functionality of Promise.prototype.then.
E.g.:
// define Searchable
let Searchable = function() {
this.searchParam = 'param';
};
Searchable.prototype = {
setSearchParam: function(p) { this.searchParam = p; },
initiateSearch: async function() {
// lots of fancy searching
console.log(`Searching with param "${this.searchParam}"`);
return `search based on "${this.searchParam}"`;
},
then: async function(callback) {
// initiate the search:
let searchResults = await this.initiateSearch();
// behave kind of like `Promise.prototype.then`!
return callback(searchResults);
}
};
// now work with it:
(async () => {
let searchable = new Searchable();
searchable.setSearchParam('mySearchParam');
console.log('No search performed yet!');
// Here's the fancy usage you're concerned with (it invokes `searchable.then`):
let searchResult = await searchable;
console.log('RESULT:', searchResult);
})();
Calling await on some value will attempt to call value.then as if it were a function accepting a callback argument.
Knex query builder is mutable and thenable object.
So every time you call for example search.where(...) for that query builder, its internal state changes and stores that new where clause.
Query builder being thenable means that the object has .then() method and when you call await search it is actually pretty much equivalent with await Promise.resolve(search) which first executes thenable and converts it to promise which is then resolved or an exception might occur.
Thenable objects are actually pretty important part of promise spec providing interoperability API between promises and non-promise objects.

Categories