had following code which worked:
let sdk = new SDK({ name: "somevalue"});
module.exports= ()=> {
sdk.dothing();
}
I then needed to change the parameter to use data from an async function:
let asyncfunc = require('asyncfunc');
let sdk = new SDK({ name: (()=>{
return asyncfunc()
.then((data) => {
return data.value
})
});
module.exports= ()=> {
sdk.dothing();
}
Following the change, the call to new SDK is failing because the parameter passed is {} as the asyncFunc promise has not yet resolved.
I'm getting back into node after a year and new to promises. what is the proper way to do this?
As you've found, you can't pass in a promise to something that's expecting a string. You need to wait for the asynchronous operation to complete.
This means that your SDK won't be ready right away, so you have two options:
Change your module so it returns a promise for the needed value. Anyone who needs to use your module would need to use the returned promise.
Example:
let pSdk = asyncFunc()
.then(data => new SDK({ name: data.value }));
module.exports = () => pSdk.then(sdk => sdk.dothing());
Store an sdk value that's not populated immediately. Users of your module can obtain the SDK instance directly, but it might not be ready when they need it.
Example:
let sdk;
asyncFunc()
.then(data => sdk = new SDK({ name: data.value }));
module.exports = () => {
if(!sdk) { throw new Error("The SDK is not ready yet!"); }
return sdk.dothing();
};
if any bit of code, in node, is asynchronous then immediately next bit of code will be executed. it doesn't matter if the asynchronous code is wrapped in promise or not.( For codes wrapped in the promise the compiler will return a pending promise to be resoled or rejected and proceed to the next bit of code.) When you are creating an object using new SDK({ }) the name is having reference to a pending promise which is yet to be settled that's why your code is failing to fulfill your requirement. You can do it this way to resolve your problem.
asyncfunc()
.then((data) => {
return new SDK({ name: data.value });
}).then(function(sdk){
//do your work here using sdk
})
One important point to be noted here is you can't return from .then() to assign the value to any variable as you are doing. The value returned from .then() will be accessible from the next chained .then() not by outside global variable.Since you are exporting sdk.dothing() so you need to export it inside the last .then()
Related
I'm creating my own package that needs to do some emitting from the package to the main file.
This simplified module gets what I'm trying to achieve:
const fetch = require("node-fetch")
module.exports.client = async function(username,password,version) {
// Do login code here
this.emit("login", loginData)
}
Then my test code runs that with
var client = new require("../index").client("username","password","0.774")
client.on("login",function(data) {
console.log(data)
})
With every time, the program returning
client.on("login",function(data) {
^
TypeError: client.on is not a function
Has anyone had a similar issue? This is my first time making a module in this style, so please let me know.
Thank you!
Because your function client() exported from index.js is declared with the async keyword, it will return a Promise rather than an actual value passed to the return statement. Assuming the value you return from the function client() is an object with an on() function, then in order to access this function you either need to await the result of client() or you need to use the .then() function on promise. Example:
var clientPromise = new require("../index").client("username","password","0.774")
clientPromise.then(client => {
client.on("login",function(data) {
console.log(data)
})
});
While you could also use await on the result of the client() function, this is not allowed in all contexts, and so you would have to wrap the code that does this in another async function.
I have a function that returns a Promise and inside that Promise I get an object in the resolve.
Here it is the function of my service that works good.
buscarUsuario(email: string){
return new Promise((resolve, reject) => {
this.http.post(`${URL}/user/email`, {email})
.subscribe(resp => {
//console.log(resp['usuario']);
resolve(resp['usuario']);
});
})
}
And then I get the value from the promise in this var:
const getDatos = this.usuarioService.buscarUsuario(this.correoUsuario.value.toString());
And then I call the var to get the value from the resolve and I can't extract that value from there:
var usuario: Usuario;
getDatos.then(usu => {
usuario = usu;
//Here I can see the value
console.log(usuario);
});
//But here I can't see the value
//And it's where I really need to get the value
console.log(usuario);
So, how do I get that value outside the Promise?
Using Promises in Angular is NOT recommended. Angular recommends use of Observable to handle asynchronous operations
Lets Try and change your code to return Observables only
buscarUsuario = (email: string) =>
this.http.post<any>(`${URL}/user/email`, {email}).pipe(
map(resp => resp.usuario as Usuario)
)
Basically the above code returns an Observable<any>(Observable of type any). I have type casted using <any> to transform the result to an Obserable<any>. Next I have use piping to extract the usuario from response
Now we can actually assign this value to a variable...
const getDatos$ = this.usuarioService.buscarUsuario(this.correoUsuario.value.toString());
NOTE: This is an Observable and you will need to subscribe to it
Observable can be assigned like any other property
const usuario: Observable<Usuario> = getDatos$
You cannot get the value outside that function, reason because since you use promise, you need to wait until the promise returns the value, so best possible way is you have do rest of your functionality within promise.then.
getDatos.then(usu => {
//implement your other functionality
});`
I am using Dialogflow to build an Action for Google Assistant. Everything works, except the Fulfillment of my intent.
I am using the Inline Editor (Powered by Cloud Functions for Firebase) to fulfill the intent. My function in itself runs - since I can send text to the assistant from the function.
But for some reason, code execution never enters the the function that fetches data from my Collection on Firebase Firestore - although it does execute commands before and after.
Here is the code in my index.js.
'use strict';
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);
let db = admin.firestore();
const {dialogflow} = require('actions-on-google');
const app = dialogflow({debug: true});
app.intent('INTENT', (conv, {ENTITY}) => {
conv.add("Hello."); //THIS IS DISPLAYED
db.collection("COLLECTION").orderBy("FIELD", "desc").get().then(snapshot => {
conv.add("Hey!"); //THIS IS NOT DISPLAYED
snapshot.forEach(doc => {
conv.add("Hi?"); //NOR IS THIS
});
conv.add("Hmm..."); //NEITHER THIS
}).catch(error => {
conv.add('Error!'); //NOT EVEN THIS
});
conv.add("Bye."); //THIS IS DISPLAYED TOO
});
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
Clearly, this shows that execution never really entered the db... block, and hence the function didn't even throw any error.
Here are the logs from Firebase.
Function execution started
Billing account not configured...
Warning, estimating Firebase Config based on GCLOUD_PROJECT. Initializing firebase-admin may fail
Request {...}
Headers {...}
Conversation {...}
Response {...}
Function execution took 1681 ms, finished with status code: 200
I know that the firestore function fetches data asynchronously, but there
seems no way I could execute anything even inside its .then(...) block.
I also tried returning a Promise from the .then(...) block, and using a second .then(...) with it - which again didn't work.
var fetch = db.collection("COLLECTION").orderBy("FIELD", "desc").get().then(snapshot => {
conv.add("Hey!"); //NOT DISPLAYED
var responseArr = [];
snapshot.forEach(doc => {
conv.add("Hi?"); //NOT DISPLAYED
responseArr.push(doc);
});
conv.add("Hmm..."); //NOT DISPLAYED
return Promise.resolve(responseArr);
}).then(fetch => {
conv.add("Here?"); //NOT DISPLAYED
}).catch(error => {
conv.add('Error!'); //NOT DISPLAYED
});
Finally, I also tried putting the firestore function in a separate function, like this.
function getData(){
return db.collection("COLLECTION").orderBy("FIELD", "desc").get().then(snapshot => {
snapshot.forEach(doc => {
...
});
return data; //Manipulated from above. 'data' can be a string.
}).catch(error => {
return error;
});
}
app.intent('INTENT', (conv, {ENTITY}) => {
conv.add("Hello."); //THIS IS DISPLAYED
conv.add(getData()); //THIS IS NOT DISPLAYED
conv.add("Bye."); //THIS IS DISPLAYED
});
The problem is that you're doing an asynchronous operation (the call to get()), but you're not returning a Promise from the Intent Handler itself. The library requires you to return a Promise so it knows that there is an async operation taking place.
Returning a Promise from inside the then() portion isn't enough - that doesn't return a value from the handler, it just returns a value that is passed to the next then() function or (if it was the last one) as the return value of the entire Promise chain.
In your original code, this can be done just by returning the get().then().catch() chain. Something like this as your first line:
return db.collection("COLLECTION").orderBy("FIELD", "desc").get() // etc etc
In your second example, the fetch in your then() block is not the fetch that you think it is, and only confuses matters. Structured that way, you need to return the fetch from the let assignment.
Your third example is more complicated. The line
conv.add(getData());
doesn't even seem like it would work, on the surface, because it is returning a Promise, but you can't add a promise to the conv object. You would need to rewrite that part as
return getData()
.then( data => conv.add( data ) );
But that doesn't address how the "Bye" line would work. If you actually wanted "Bye" after the data, you would have to include it as part of the then() block.
In short, when dealing with async data, you need to
Make sure you understand how Promises work and make sure all async work is done using Promises.
Add all your data inside the then() portion of a Promise
Return a Promise correctly
I'm accessing google API for converting coordinates into detailed objects using node-geocoder library from npmjs. Everything went well and I'm getting the expected object from geocoder API. The problem started the moment when I thought of using the data outside the promise function. I want to use the values outside the promise/async-await function.
Below is the code I've tried, Pls take a look and help me. TIA...
function goecoderPromiseFunction() {
return new Promise(function (resolve, reject) {
geocoder.reverse({ lat: 45.767, lon: 4.833 })
.then(data => {
cityName = data[0].city;
resolve(cityName);
})
.catch(err => {
console.log(err);
});
});
}
async function app() {
var a = await goecoderPromiseFunction();
return a;
}
var a = app();
console.log("a->", a);
I expect the variable "a" should print the city name "Lyon", but it prints
a-> Promise { < pending > }
The promise returned by the app function is never consumed, that is why it remains in a pending state.
Call then on the app function to get the result :
app().then(a => console.log("a->", a));
You can also use async/await :
(async function() {
var a = await app();
console.log("a->", a);
})();
An asynchronous function actually returns a promise that 'resolves' to the function's return value. You are therefore assigning a promise to the value of a. If you are in the global scope, you obviously cannot use async/await so you need to use either a self-executing async function or you need to run
a.then(data => console.log('a->', data));
to get what you are looking for.
Find out more about async functions here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
It prints because console.log("a->", a); runs while promise haven't returned answer for a variable "a"
Note: you haven't used reject function, if there is an error you wont notice and may be that error was the required answer to be carried by variable "a" that's why it still pending i.e still waiting.
For more idea try to use reject function inside the catch block example reject(err)
instead of console it out as you've done
I thought I had it all figured out regarding Promise, but this one actually throws me out of bed. When creating a new Promise with a executor taking two arguments, why is this method running before I either take then() or catch() at that promise
Running node 6.2.2.
import assert = require('assert');
describe("When working with promises", () => {
let ar = [1, 2, 3, 4, 5, 6];
beforeEach(() => {
})
it("should be perfectly fine but isn't when mapping to promises", (done) => {
ar.map(num => {
return new Promise((resolve, reject) => {
done(new Error('Why on earth is ' + num + ' called'));
})
})
done();
})
it("should be perfectly fine when mapping to methods", (done) => {
ar.map(num => {
return (resolve, reject) => {
done(new Error(num + ' is not called ever'));
}
})
done();
})
});
First test fails, and second test is successful.
If you check the documentation for Promise, you will find that the function that is given to the constructor is run immediately. It is supposed to kick off the asynchronous calculation and install the two callbacks there (so that resolve and reject are not invoked just now, but whenever that calculation completes or fails).
The Promise function is not the asynchronous calculation, it just wraps that calculation and the two callbacks you need to keep track of it together into a nice package (and returns immediately after this setup is done).
Your second example creates an anonymous function for each number, but does not invoke any of them.
why is this method running before I either take then() or catch() at that promise
The Promise does not care if you install any handlers/chains. The calculation will have been started (or not) no matter if anyone is watching it or not.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise:
[...] The executor function is executed immediately by the Promise implementation, passing resolve and reject functions [...].
That's the way, the Promise implementation works. You can also create a new promise and attach chained then() or catch() handlers later when the promise already succeeded or failed.
const p = new Promise(someExecutor);
// do some other things
p.then(someHandler);
// do some other things
p.catch(someOtherHandler);
If you do not want the executor to execute, yet, then don't pass it to the Promise constructur, yet.
To achieve the same behavior you have to wrap promises in a factory. You can use a lambda functions for that.
it("should be perfectly fine but isn't when mapping to promises", (done) => {
ar.map(num => {
return () => new Promise((resolve, reject) => {
done(new Error('Why on earth is ' + num + ' called'));
})
})
done();
})
So you have stateless factories to call later without creating promises (that run immediately) during map.
It permits you to compose and join Promises for later batch execution using Promise.all, Promise.race, or custom chaining.
If you want something to run only (i.e. not before) a "then()" handler is attached, then you can use plain then-ables ( https://promisesaplus.com/ )
var runLater = {
then: function(resolve, reject) {
var p = new Promise (...); // Creating a promise is optional
resolve(p); // you can return a plain value
}
}
Note this is not a Promise, so it does not have a "catch" method.
But it can be given to any function expecting a promise:
`Promise.all([runLater])
return as result from a then handled .then(function() { return runLater; })
Promise.resolve(runLater) => Now it is a promise with then/catch
Any of those will call the runLater.then method.