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
Related
Currently, I keep receiving Promise, and the error User localuser was in an empty topic named 'random'.
My code is structured like this
const bot = new RiveScript();
bot.loadDirectory("./brain");
bot.sortReplies();
Below is in a function
// blah
if (text === 'blah') {
return {
attachment: blah()
};
}
// No command is correct
return {
text: getReply(text)
};
function getReply(msg) {
const reply = bot.reply("localuser", msg);
return reply;
}
I've been trying everything, but I still need help getting a result where the text goes into the function and returns a reply from the RiveScript. I also ran debug, so the RiveScript files are definitely being read. I also tried using async functions and await for getReply but it doesn't work either.
I'm not overly familiar with RiveScript, however checking their GitHub, loadDirectory is an asynchronous function which would show as Promise<Pending> until the Promise has resolved (or is rejected).
You need to wait for the Promise to resolve before moving on in your code. Read up on asynchronous javascript or node, because there is a lot to learn! https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous is a good start!
To start you off with your example:
const bot = new RiveScript();
bot.loadDirectory("./brain").then((response) => {
//Once loadDirectory is complete then do this...
bot.sortReplies();
});
then() will wait until the Promise has resolved before executing bot.sortReplies().
Note that .reply() also returns a Promise according to the ReadMe (https://github.com/aichaos/rivescript-js). So:
//bot.reply is asynchronous to you need to await the Promise to resolve before returning.
async function getReply(msg) {
return await bot.reply("localuser", msg);
}
Hopefully this gives you something to play with!
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())
I'm trying to wrap my head around Nodejs and Promises and I'm seeing a behavior I don't quite understand so I'd like to get some help from the experts :)
I have trainStations.js file that returns information and caches it using node-cache library.
async function getTrainStations(){
var stations = await knex.select()
.from('TrainStations')
stations.forEach(
item => cache.set(item['code'], item['name'])
);
knex.destroy();
return cache;
}
module.exports = {
getTrainStations
};
Then. in app.js file, I call it as:
const stations = (async () => {
let res = await stationsModule.getTrainStations();
return res;
})();
If I debug "res" it is clearly a node-cache object, I can call the get method with a key and get its value. However, when it gets assigned to stations, it does it in the form of a resolved promise, and when I debug I can see the values, but I can't figure out how to return the value of the promise and use it as I want.
So basically the question is, why "res" got a proper node-cache object, but later on when I want to use "stations" I have a resolved promise instead. And also, how do I access to the values within the resolved promise? I tried with .then() and I can print the values in a console.log but can't use them at all.
Thanks in advance for the help!
async function calls always return a promise for the result of an [asynchronous] operation. In
const stations = (async () => {
let res = await stationsModule.getTrainStations();
return res;
})();
stations is assigned the promise returned by the anonymous arrow function call const stations = (async () => {...})();
The promise will be resolved with res when the data becomes available.
It may be worth noting you can't return an asynchronous result (obtained in the future) to the same call out from the event loop that requested the operation. In that turn of the event loop the result is pending.
Once await has been used, all code using the result must be in an async function, accessed using promise handlers in ordinary code, or triggered by a timer or event fired after the data arrives.
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.
I have this code jQuery code fragment:
$.get('/api/' + currentPage).done(function(data) { ... })
.fail(...)
I want to replace $.get('/api/'+currentPage) with a promise that always succeeds and returns a specific value for data. Something like:
let myData = { ... } // value of data I want to pass to the done function
(new AlwaysSucceeds(myData)).done(function(data) { ... })
.fail(...)
I could cobble up a dummy object, or I could extract out the done function but I want to keep changes to the code to a minimum.
Is there a way to do this?
UPDATE: To help clarify what's going, the code I am working with is (here). Normally this app is served from a nodejs server which implements the /api/... call, but I am converting it to be served
from a static page server. I know what is going to be returned from
the $.get call. To keep changes to the code clean I simply want to
change that line to:
let myData = {...}
// $.get('/api/' + currentPage) -- comment out the $.get call
(SOMETHINGHERE(myData)).done(function(data) {
The SOMETHINGHERE expression needs to implement .done(f)
which will call the function f with myData and then return
some object which implements .fail(...) which does nothing.
You can just replace $.get(...) with a function that returns a promise that is already resolved with the data you already have. And, the shortest way to get an already resolved jQuery promise, resolved with a particular value, is this:
$.when(myData).done(...)
The more text book way to do it in jQuery is:
$.Deferred().resolve(myData).done(...)
And, if you care to switch your logic to the the ES6 standard (instead of the non-standard jQuery promise behaviors), then you could use this:
Promise.resolve(myData).then(...).catch(...)
You can achieve this by implementing AlwaysSuceeds constructor function. Please see below example.
function AlwaysSucceeds(data) {
this.data = data;
}
AlwaysSucceeds.prototype.done = function(fn) {
fn(this.data);
return this;
}
AlwaysSucceeds.prototype.fail = function(fn) {
return this;
}
var myData = {
a: 1
};
(new AlwaysSucceeds(myData)).done(function(data) {
console.log(data)
}).fail(function(data){
})
Since jQuery Ajax functions just return $.Deferred objects, you can just substitute an immediately-resolved Deferred:
$.Deferred().resolve(myData).then(...)
In this particular case, if you want to make it easy to switch between synchronous and asynchronous code, and you have access to async/await, you can just use those directly:
try {
const data = await Promise.resolve($.get('/api/' + currentPage));
// code in done
} catch (err) {
// code in fail
}
would become
try {
const data = myData;
// code in done
} catch (err) {
// code in fail (never runs unless other code throws exceptions)
}
It's not clear what you actually want but be carufull using jQuery Deferred with native promises, the deferred has some non standard methods that native promises don't have.
So to be save I always assume there is a thenable, something that has a then with that you can pretty much do whatever you want.
jQuery Deferred do not behave like native promises either (depending on version):
$.Deferred().reject("hello world")
.then(
undefined
,x=>x
)
.then(
x=>console.log("Never happens",x)
)
Promise.reject("hello world")
.then(
undefined
,x=>x
);
.then(
x=>console.log("Well behaved",x)
);
Promise.resolve().then(x=>{throw "nope"})
.then(undefined,err=>console.warn(err));
$.Deferred().resolve().then(x=>{throw "nope"})//crashes
.then(undefined,err=>err);
So it will be saver to use native promises and polyfill with something that behaves like native.
To answer the question about non failing promise, if you want to make a request but return a default when it rejects and keep returning the same once resolves or rejects you can do:
const get = (p=>{
(url) => {
p = p ||
//return native promise or properly polyfilled one
Promise.resolve($.get(url))
.then(
undefined,
_=> {defaultobject:true}
);
return p;
}
})();
Your get function will return a native promise so no fail, done and other things that are non standard. Combining "promises" from different libraries and native promises it would be best to only use then