I was reading How to use MongoDB with promises in Node.js? when I saw that in the first answer they say that if I pass no callback, mongo driver will return me a promise. It worked for 'connect' but it didn't work when I tried:
db.collection('myCollection').find().then((docs)=>{console.log(docs)})
I got:
MongoDB error: TypeError: db.collection(...).find(...).then is not a function
I tried to read the documentation for find() at http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#find and I can see some examples there that does things like this:
collection.find({}).explain().then(function(docs) {
test.ok(docs != null);
db.close();
});
this is a Promise for find but it has this explain() thing. What is it? Also, why there is no mention of promises in this API? There's also another line that does:
collection.insertMany([{a:1}, {a:2}, {a:3}], {w:1}).then(function(result) {
which is also a promise.
So, how to use promises with find()?
Also, why this documentation won't tell the return values of anything? Neither the arguments I can use...
What you are looking for is toArray(), which works like you want (callback inside, or promise returned if not callback)
db.collection('...').find().toArray()
.then(function(docs) {
// =)
});
This is because db.collection('..').find() returns a cursor, not a promise.
This behavior is intended because "find as a whole" is not the only pattern that can be used (ie. streams are allowed).
Related
I'm coming from a PHP background and I'm trying to learn NodeJS.
I know that everything in Node is async but I've found that i've been using the async / await combo quite a lot in my code and I wanted to make sure I wasn't doing something stupid.
The reason for it is that I have a lot of situations where I need the result of something before continuing (for example for a small ajax request). This small ajax request has no other purpose other than to do the set of things that I want it to and in the order that I specify so even if I do things the "async way" and write it using a callback i'm still having to wait for things to finish in the right order.
Right now whenever I find myself in this situation I just use await to wait for the result:
ie:
var result = await this.doSomething(data);
Opposed to using a callback
this.doSomething(data, function(callback) {
// code
callback();
});
To me the first example looks cleaner than the second one which is why I've been opting for that. But I'm worried that I might be missing something fundamental here. But in a situation where there is nothing else to process below the async call and the only way for things to progress is for it to follow a syncronous style, is there anything wrong with using the first style over the second?
But I'm worried that I might be missing something fundamental here.
Nope, you're not, that's exactly what you want to do, assuming this.doSomething(data) is asynchronous (and if it's an ajax call, one hopes it is async) and that it returns a promise (which all functions defined with the async keyword do implicitly). (If it's not asynchronous, you don't need the await, although it's allowed.)
You're probably being a bit confused (understandably) by the fact that things are going through a transition. Until recently, the overwhelming convention in Node APIs (the built-in ones and ones provided by third-party modules) was to use the "Node callback" pattern, which is that a function that will do asynchronous work expects its last argument to be a callback, which it will call with a first argument indicating success/failure (null = success, anything else is an error object) with subsequent arguments providing the result. (Your second example assumes doSomething is one of these, instead of being a function that returns a promise.)
Example: fs.readFile, which you use like this:
fs.readFile("/some/file", "utf-8", function(err, data) {
if (err) {
// ...handle the fact an error occurred..
return;
}
// ...use the data...
});
This style quickly leads to callback hell, though, which is one of the reasons promises (aka "futures") were invented.
But a lot of Node APIs still use the old pattern.
If you need to use "Node callback"-pattern functions, you can use util.promisify to create promise-enabled versions of them. For instance, say you need to use fs.readFile, which uses the Node callback pattern. You can get a promise version like this:
const readFilePromise = util.promisify(fs.readFile);
...and then use it with async/await syntax (or use the promise directly via then):
const data = await readFilePromise("/some/file", "utf-8");
There's also an npm module called promisify that can provide a promise-ified version of an entire API. (There's probably more than one.)
Just because promises and async/await replace the old Node callback style in most cases doesn't mean callbacks don't still have a place: A Promise can only be settled once. They're for one-off things. So callbacks still have a place, such as with the on method of EventEmitters, like a readable stream:
fs.createReadStream("/some/file", "utf-8")
.on("data", chunk => {
// ...do something with the chunk of data...
})
.on("end", () => {
// ...do something with the fact the end of the stream was reached...
});
Since data will fire multiple times, it makes sense to use a callback for it; a promise wouldn't apply.
Also note that you can only use await in an async function. Consequently, you may find yourself getting into the habit of a "main" module structure that looks something like this:
// ...Setup (`require` calls, `import` once it's supported, etc.)...
(async () => {
// Code that can use `await `here...
})().catch(err => {
// Handle the fact an error/promise rejection occurred in the top level of your code
});
You can leave the catch off if you want your script to terminate on an unhandled error/rejection. (Node doesn't do that yet, but it will once unhandled rejection detection matures.)
Alternately, if you want to use a promise-enabled function in a non-async function, just use then and catch:
this.doSomething()
.then(result => {
// Use result
})
.catch(err => {
// Handle error
});
Note: async/await is directly supported in Node 7.x and above. Be sure your target production environment supports Node 7.x or above if your'e going to use async/await. If not, you could transpile your code using something like Babel and then use the transpiled result on the older version of Node.
All morning I've been trying to get the AsyncStorage.getItem to return the value of the actual item, not a promise.
Here's what I have that according to everything I've read should work:
export async function getToken(){
try{
var value = await AsyncStorage.getItem('authToken');
return value;
}catch (error){
console.log(error);
}
}
I have tried chaining together many .thens, tried accessing the actual value field of the promise, but for some reason that returns a promise also. I've tried pretty much every suggestion on this site and it will always return a promise.
Quoting the AsyncStorage documentation
... Each method in the API returns a Promise object.
and also based on this post, there is no way for you to access the value without the use of promise or any other async patterns (generators, callback etc).
You can use Realm as a storage without using promises. This is how you query data in realm (quoting the documentation):
let token = realm.objects('authToken'); // retrieves all authTokens
Using bluebird promises, I am trying to check if a certain version of a file exists (always only ONE of those files exists but i don't know which one). To speed things up, I am using the any() collection to get all checking out concurrently:
Promise.any([
fs.existsAsync('./foo/image1.jpg'),
fs.existsAsync('./foo/image2.gif'),
fs.existsAsync('./foo/image3.png')
]).then(function(result) {
console.log(result); //remains undefined
});
I am always getting an undefined result. According to (How do I return the response from an asynchronous call?) this is normal behaviour of a resolved promise. Still, I need to know, which of my three promises resolved or maybe I just can't use any() for that purpose?
The callback for fs.exists() does not follow the expected calling convention of callback(err, value) so it doesn't work with generic promisify. It uses just callback(value).
You could either use fs.statAsync() instead or you could create your own promisification for fs.exists() that would work properly.
Of course, fs.exists() is deprecated anyway for race condition reasons so you should perhaps rethink your tactic here anyway.
Here's a properly promisified fs.existsAsync():
fs.existsAsync = function(path) {
return new Promise(function(resolve) {
fs.exists(path, resolve);
});
}
You would assign this after you've done the general promisification of the fs module to replace the wrong fs.existsAsync that Bluebird did automatically.
Ive been trying to find the simplest JavaScript promise(without libraries) so i can get it into my thick skull. Thought i was getting the concept, but seem to be unable to work it. Can anyone fix this?
function fetch(message){
return message;
}
var promise = fetch('beep')
promise.then(function(dMessage){
console.log(dMessage);
}).catch(function(err){
console.error('error-', err);
})
ERROR Message:promise.then is not a function
Am also a little confused about when i can use this? NodeJs will be able to use this without extra libraries right? for client side i should get ES6-promise?
Solution underneath with thanks to Daniel B
function fetch(message){
return new Promise(function(resolve, reject){
resolve(message);
});
}
fetch('word').then(function(dMess){
console.log(dMess);
}).catch(function(err){
console.error('error-', err);
})
You are overwriting the native fetch function. Simply remove your function and it will work.
If you want to define your own fetch function, it has to return a promise, as below.
function fetch(message){
return Promise.resolve(message);
}
I don't believe the other answer is correct. Although it's correct in 'fetch' is a method native to browsers (not javascript which the user implied) it is not the reason why your promise doesn't work, and doesn't explain what you're not understanding about promises.
The first 'promise' in a chain always has to be a promise constructor/instance. You can create these in many ways, but if you have only a simple value like a string, you must wrap it in Promise.resolve(string). Afterwords, and other promises in the chain won't need this functionality as they are all wrapped in the top level promise of the chain. At least this is how most implementations like Q/Bluebird/ES6 Native promises will work.
I have the following code:
return Promise.settle(matches, imgur.uploadUrl)
.map(function (inspection) {
if (inspection.isFulfilled()) {
return inspection.value().data.link;
}
return '#';
})
A more verbose version of the above displays the same problems:
return Promise.settle(matches, function(match) { return imgur.uploadUrl(match); })
.then(function(results) {
return results;
})
.map(function (inspection) {
if (inspection.isFulfilled()) {
return inspection.value().data.link;
}
return '#';
})
Where
Promise = bluebird's promise
matches = an array of image links extracted from a string
imgur = https://github.com/kaimallea/node-imgur
The expected behavior is that the result of .map is a promise which resolves with an array of imgur links after the images in the original array was uploaded to imgur (or '#', in case the upload failed for any reason).
What happens instead is that Promise.settle resolves instantly (i.e. doesn't seem to wait for the imgur uploads), and inspection.value() is the original image url from the matches array (which gives an error when trying to read the .data.link property of a string).
Why does this happen? Why won't it upload to imgur and resolve correctly?
When I look at the Bluebird source for Promise.settle(), I only see that it processes the first argument (expecting an array of promises). I've always just used it as a substitute for Promise.all() when you want all promises to complete, even if some have errors.
I wonder if the Bluebird documentation for .settle() is just wrong about it taking a function as the second argument that will process the first array? The code is a little hard to follow, but I don't see how Promise.settle() ever uses the 2nd argument (unless this isn't the right code I'm looking at for some reason).
As you pointed out, an alternative is:
Promise.settle(matches.map(imgur.uploadUrl)).then(...)
which just passes an array of promises to .settle().
FYI, I verified by creating a simple test case and stepping into Promise.settle() in the debugger that it never uses the second argument passed to it. This appears to be a case of the documentation not matching the implementation. I expect someone planned to implement what is documented, but never completed that implementation.
This was indeed a bug in the docs. It was fixed (props to OP for the pull request).
The docs now show the correct usage of .settle.