I want this function tagFindOrCreate to only execute if the first function is finished:
func.tweetCreate(bmTweet, user)
.then(function () {
func.tagFindOrCreate(bmTweet, bmtTag, user)
})
Help me create a promise for this function:
tweetCreate: function (tweet, user) {
Tweet.create(tweet, function (err, tweet) {
user[0].tweets.push(tweet)
user[0].save()
console.log("Tweet saved.")
return Promise.resolve()
})
}
This would be as follows:
tweetCreate: function (tweet, user) {
return new Promise(resolve => {
Tweet.create(tweet, function (err, tweet) {
user[0].tweets.push(tweet);
user[0].save();
console.log("Tweet saved.")
resolve();
})
}
};
Since Tweet is a mongoose model, its create method will already return a promise as long as you don't pass a callback. This means you can move your callback logic to where promise resolution occurs. The simplest way to do this would be to use an async function.
tweetCreate: async function (tweetContents, user) {
const createdTweet = await Tweet.create(tweetContents);
user[0].tweets.push(createdTweet);
user[0].save();
console.log('tweet saved');
}
A note on error handling: An async function will already return a promise or potentially throw an error (if there is an error in Tweet.create). The above code will propagate the error, so make sure that if you are using async/await you wrap your calling code in try/catch or make use of .catch to handle the errors where it's needed. It's up to the logic of your app to decide whether you need to catch the error in tweetCreate itself, or whether you can propagate it into the application code level where it can be caught and handled, but just be aware of the need to handle potential promise errors.
For the sake of completeness, you can promisify Tweet.create. It's common for library methods to return promises nowadays, so manual promisification is rarely necessary. Keep this in mind if you feel the need to promisify ... the library may already have a mechanism for it.
You can do this manually simply by using a Promise constructor. This takes a callback which takes a resolve argument which you can call from within another callback to resolve the promise:
return Promise(resolve => {
Tweet.create(tweet, (error, createdTweet) {
...
resolve();
});
});
Node.js has a built-in promisify function as well, so using a Promise constructor is probably unnecessary for this purpose. You could do:
const createTweet = util.promisify(Tweet.create);
const createdTweet = await createTweet(tweet);
...
NOTE: the above is just an example. It's not necessary to do this with mongoose models.
You need to use the promise constructor to create a promise and tweetCreate() should return that promise.
Call to Tweet.create(...) should be inside the executor function (function that is passed to the promise constructor) and from inside of the callback function of Tweet.create(...), you need to call the resolve() function to fulfil the promise.
You need to change the implementation of your function to as shown below:
tweetCreate: function (tweet, user) {
return new Promise((resolve, reject) => {
Tweet.create(tweet, function (err, tweet) {
user[0].tweets.push(tweet);
user[0].save();
resolve(); // <--- this will resolve the promise
});
});
}
Calling resolve() will fulfil the promise leading to the invocation of the callback function of the then() method.
Edit
You mentioned in a comment that Tweet is a mongoose model; In that case, you don't need a explicitly create a promise. Mongoose provides a promise-based API for creating and saving documents in the database and that is what you should use instead of creating promises yourself.
Related
To profile my app more detailed I need to know which promises not awaited but... js not provide such ability.
In python every time when result of async function is not awaited it prints warring
But how to obtain such result in js?
I concluded to do so I have to know few things:
how to override promise construction (to add state field which will show is promise awaited and to set timeout to check state)
what triggered when object awaited (to change state)
I figured out via Proxy that when awaiting, object's then property is called:
async function test(obj) {
await obj
}
test(new Proxy(new Object(), {
get(obj, name) {
console.log("get " + name)
}
})
But actually, as turned out, it happens only with non-promise objects
So when I tried to do this:
Promise.prototype.then = function() {
console.log("called then")
}
test(Promise.resolve({}))
I got nothing in output.
Same things with Promise.prototype.constructor and Promise.resolve:
let getOne = async () => 1
getOne()
getOne neither call Promise constructor nor Promise.resolve.
So what I'm doing wrong ?
How actually async/await creates promises and fetch value from them under the hood, and how can it be overridden ?
I figured out via Proxy that when awaiting, object's then property is called
Indeed, that is correct.
when I tried to do [...] test(Promise.resolve({})) I got nothing in output.
That is because in this code -- contrary to your earlier test with await -- you do not execute an await or a then call here. You just construct a promise, and your proxy object is not trapping the creation of a promise, only the execution of the then method.
This brings us back to your first bullet point:
how to override promise construction?
You cannot.
We have access to the Promise constructor, but there is no way you can trap its execution. If you would make a proxy for it -- with a construct handler -- it would not be called, as the JavaScript engine will still refer to the original Promise constructor when -- for instance -- an async function is executed. So you are without hope here.
I don't believe overriding is something you want. Usually async is telling node that this function is asynchronious and if you have something in the event loop that is "long" procedure such as querying another API or reading IO then those functions will yield promises. You can also try using the following:
return new Promise((resolve, reject) => {... do stuff and call resolve() or reject() based on the expected output})
The returned value will be a promise.
To handle the promise you will need to await it.
To get promise from
let getOne = async () => 1 you will need to make it
let getOne = async () => return new Promise((resolve, reject) => return resolve(1))
To obtain the value later you will need to call await getOne()
Since inside a Observable we have an option of calling Promise ,I have a clarification regrading this.
Since a promise gets executed immediately after declaration , will it be executed without attaching Subscribe method to it ?
And also since it cannot be cancelled why would anyone think of calling a Promise inside a observable .
Rx.Observable.fromPromise():
const computeFutureValue = new Promise((resolve, reject) => {
//make http api call
});
Rx.Observable.fromPromise(computeFutureValue)
.subscribe(
val => {
console.log(val);
},
err => {
console.log(`Error occurred: ${err}`);
},
() => {
console.log('All done!');
});
As you said, a Promises body is executed when you create the Promise.
So when you create this Promise:
const computeFutureValue = new Promise((resolve, reject) => {
//make http api call
});
the http request is executed no matter what you do next. Using from (or fromPromise) to convert the Promise to an Observable and subscribing to this Observable doesn't affect the Promise and it's execution in any way.
You'd want to convert a Promise to an Observable if you want to be able to work with all the operators Observables offer or because your app works with and requires Observables at certain points.
If you only want to create and execute a Promise when you subscribe to an Observable you can use defer, see my answer here: Convert Promise to Observable
I have abstraction:
function fetchDataFromAPI() {
const url = `https://api...`
return fetch(url).then(response => response.json())
}
I want to use it in my other piece of code like:
if(something){
const data = fetchDataFromAPI()
return data
}
if I console.log data what I get is resolved pending promise
PromiseĀ {<pending>}
__proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: Object
How do I get that Object in data instead of Promise?
You can not. Here is why:
Promise is a language construct that makes JavaScript engine to continue to execute the code without waiting the return of inner function, also known as the executor function. A promise always run inside the event loop.
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('foo');
}, 300);
});
console.log(p);
Basically a promise is a glorified syntactic sugar for a callback. We will see how but first lets have a more realistic code:
function someApiCall(){
return new Promise(function(resolve, reject){
setTimeout(()=>{
resolve('Hello');
})
})
}
let data = someApiCall();
console.log(data);
This is a so-called asynchronous code, when JavaScript engine executes it, someApiCall immediately returns a result, in this case pending promise:
> Promise {<pending>}
If you pay attention to the executor, you will see we needed to pass resolve and reject arguments aka callbacks. Yes, they are callbacks required by the language construct. When either of them called, promise will change its state and hence be settled. We don't call it resolved because resolving implies successful execution but a function also can error out.
How do we get the data? Well we need more callbacks, which will be called by the executor function once the promise is settled:
var p = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('foo');
}, 300);
});
p.then((result) => {
console.log(result); // foo
}).catch((err) => {
console.log(err);
});
Why we need to pass separate callbacks? Because one will be fed to the resolve, and the other to the reject. Then callback will be called by the resolve function, the catch callback by the reject function.
Javascript engine will execute these callbacks later on its leisure, for a regular function it means when the event loop is cleared, for timeout when the time is up.
Now to answer your question, how do we get data out from a promise. Well we can't.
If you look closely, you will see we don't really get the data out but keep feeding callbacks. There is no getting data out, but passing callbacks in.
p.then((result) => {
console.log(result);
}).catch((err) => {
console.log(err);
});
Some say use await:
async function() {
let result = await p;
}
But there is a catch. We have to or wrap it in async function. Always. Why? Because Async/await is another level of abstraction or syntactic sugar, whichever you prefer, on top of promise api. That is why we can not use await directly but always wrap it in async statement.
To sum up, when we use promise or async/await we need to follow certain convention and write terse code with closely knitted callbacks. Either javascript engine or transpilers like babeljs or typescript converts these code to regular javascript to be run.
I can understand your confusion because people keep saying getting data out when talking about promises, but we don't get any data out but pass callback to be executed when the data is ready.
Hope everything is clear now.
No, you cannot without using promises or async/await etc because calling a REST API is an asynchronous operation and is non blocking.
When you make a call to a REST API, the code shouldn't wait until the API returns a value because it may take a lot of time, making program non-responsive, thus by design making a network request is categorized as an asynchronous operation.
To avoid async/await, you'll need to use another .then:
if (something) {
return fetchDataFromAPI()
.then((data) => data /* you can console.log(data) here */)
}
I have a Meteor.method() that server side returns a promise from oracledb. Client side I have:
Meteor.call('myMethod', (error, result) => {
result.then() // err -> no .then() method?,
});
So what is result? It does not have a .then() method, so it is not a promise?
Meteor does not "send" the promise to the client.
The server returns a result value to the client (which triggers the callback) once the promise is resolved (or rejected) on the server, and not at the moment the promise is returned from the method itself (unless it is already settled when returned).
You can also use async/await to simplify the code.
Here is a blog post with more details about the using asynchronous code in methods.
Note:
The value sent from the server is serialized using EJSON. Object methods, getters, etc. are stripped from it, unless you create a custom serializer. In some cases, serialization might even fail (I think it happened with certain moment objects) and result in undefined being returned.
Meteor is not using promises by default, however, you can wrap your Meteor.calls into a promise function as below
const callWithPromise = (method, myParameters) => {
return new Promise((resolve, reject) => {
Meteor.call(method, myParameters, (err, res) => {
if (err) reject('Something went wrong');
resolve(res);
});
});
}
(async function() {
const myValue1 = await callWithPromise('myMethod1', someParameters);
const myValue2 = await callWithPromise('myMethod2', myValue1);
})();
Sample code has copied from Meteor forum.
Also, this topic gives you a better insight in taking advantages of Aysnc/Await syntax or Promises in Meteor calls.
I am trying to understand deferred and promise. I dont want to use any library angularfire etc., before understanding the core concept. This is what i am trying to do and always getting a wrong status. Please advise.
........
var defObj = $.Deferred();
var fbref = new Firebase(<<firebase url>>);
defObj.done(function() {
console.log('Success')
}
);
defObj.fail(function() {
console.log('Fail')
}
);
defObj.resolve(
fbref.authAnonymously(function(error, authData) {
if (error) {
defObj.reject();
}
/*
else if (authData) {
defObj.resolve();
}
*/
});
return defObj.promise();
........
Pls ignore any syntax errors. Earlier I wrapped the fbref.authAnonymously call in a seperate function. In debug mode it was falling to fail but in run mode it was always going to success.
I am sure my firebase instance is not enabled for anonymous authentication.
edited : misspelt title.
Promises are now an official part of JavaScript and you can use them in the latest browsers without a library.
function authAnonymously() {
// 1
var promise = new Promise(
function(resolve, reject) {
var ref = new Firebase(<<firebase url>>);
ref.authAnonymously(function(error, authData) {
if (error) {
reject(error); // 2
} else {
resolve(authData); // 3
}
});
});
}
authAnonymously()
.then((authData) => console.log(authData)) // 4
.catch((error) => console.error(error)); // 5
Here are the five steps in this example
Create a Promise constructor
If the asynchronous action is to error, mark it with the reject() function.
If the asynchronous action is to succeed, mark it with the resolve() function.
Call the authAnonymously() function and begin the promise chain with the then() function. When successful this function will fire off.
Continue the promise chain with the error() function. If the error occurs, the catch() function won't fire, but this error() function will.
Promises work well for one time callbacks. For Firebase, this is great for authentication methods and once() calls. This is not great though for repeated callbacks, like the on() function.