2

Probably worded poorly, I understand async/promises/callbacks.

What I'm trying to do is create a module which can be required (database.js), which I can then call methods such as database.insert() and database.read().

So here is my code:

require('dotenv').config()
const {MongoClient} = require('mongodb');
const client = new MongoClient(process.env.MONGO_URI);

var db, queue;

client.connect().then(e => {
    console.log('connected to database');

    db = client.db('filemanager');
    queue = db.collection('queue');
});

function insert (data, cb) {
    queue.insertOne(data)
        .then(res => {cb()})
}

module.exports = {
    insert: insert,
}

The question is: How do I make it so when database.insert() is called, it will process instantly if db and queue are already defined, but if they aren't it will wait until they are, then will continue processing like normal?

stackers
  • 2,701
  • 4
  • 34
  • 66

1 Answers1

3

You can assign the result of a promise to a variable, and you can call then on it later. For example:

const queuePromise = client.connect().then(e => {
    console.log('connected to database');

    const db = client.db('filemanager');
    const queue = db.collection('queue');

    return queue;
});

Now you have a variable called queuePromise that is a Promise that resolves to a db.collection object. Then you can use that promise like this

queuePromise.then((queue) => {
    // do something with the queue
});

So you can have a function like this

const insert = (data, callback) => {
    queuePromise.then((queue) => {
        queue.insertOne(data).then(callback);
    });
};

Or even better, don't use the callback pattern and go like this

const insert = (data) => {
    return queuePromise.then((queue) => {
        return queue.insertOne(data);
    });
};

// use the callback in a `then` after calling `insert`
insert(data).then(callback);
nullromo
  • 2,165
  • 2
  • 18
  • 39
  • Thanks, it looks good but I have a few questions if you dont mind: 1. So in the first snippet, is the same promise that connect() returns assigned to queuePromise, even though you call .then at the end? 2. In the second snippet, did you mean to write queuePromise.then()? 3. So once a promise is resolved, I can can still call .then() on it, and it will just return the value instantly? 4. In example 4, how come it returns the insertOne promise, and not the result of queuePromise, because it gets returned inside queuePromise.then()? – stackers Aug 21 '21 at 00:49
  • 1
    @stackers For your questions 1, 3 and 4, you'll want to have a look at [how the `.then()` method works](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then). Such chaining is [the core principle of promises](https://stackoverflow.com/a/22562045/1048572). – Bergi Aug 21 '21 at 23:34
  • 1
    @stackers 1. Yes, you can chain promises together and call `.then()`, `.catch()`, or `.finally()` as many times as you want. 2. Whoops, fixed. 3. Yep :) 4. `return queue.insertOne(data)` returns a value, which means that the `queuePromise.then()` part is going to return a promise that resolves to that same value. Then the `insert` function will return that promise. So `insert` returns a promise that resolves to the result of the `insertOne` function. On the very last line, we can use that promise and call `.then()` on it again with whatever callback we want. – nullromo Aug 23 '21 at 16:26