简体   繁体   中英

Execute a jQuery function after 2 others were finished

In my project I have two functions that retrieve respectively the number of completed tasks, and the number of uncompleted tasks. (I use NeDB but it does not matter).

After that, I want to add together these two numbers.

Here is my code :

var completed = 0
  , uncompleted = 0;

// Get completed tasks
db.find({ completed: true }, function (err, tasks) {
   completed = tasks.length;
   console.log(completed); // output 7
});

// Get uncompleted tasks
db.find({ completed: false }, function (err, tasks) {
   uncompleted = tasks.length;
   console.log(uncompleted); // output 3
});

// This line is executed before the lines above
console.log(completed+uncompleted); // output 0 (I would like to output 10)

As you see the last line output 0 because it is executed before the two functions have finished.

So my question is how to make the last line output 10 ?

I think I have to use promises, but I read a lot of topics on SO and there is a lot of different approaches (with promise, then, done, deffered, array of promises, functions in variables ...) so I'm a little bit lost.

I wanted to know what is the correct way to do that :)

I tried this code, but I think I am completely mistaken ...

  var completed = 0 , uncompleted = 0; // Get completed tasks var getCompleted = function(){ return db.find({ completed: true }, function (err, tasks) { completed = tasks.length; console.log(completed); // output 7 }); } // Get uncompleted tasks var getUncompleted = function(){ return db.find({ completed: false }, function (err, tasks) { uncompleted = tasks.length; console.log(uncompleted); // output 3 }); } var promises = []; promises.push(getCompleted()); promises.push(getUncompleted()); $.when.apply($, promises).done(function () { console.log(completed+uncompleted); // output 0 }); 

The NeDB library you are using does not return promises - you can perform your work in nested callbacks like this:

db.find({completed: true}, function(err, completeTasks) {
  db.find({completed: false}, function(error, incompleteTasks) {
    console.log(completeTasks.length + incompleteTasks.length);
  });
})

If you want to use Promises, first you'll need to promisify any asynchronous tasks that don't return a promise

In your case

A

function dbFindPromise(db, params) {
    return new Promise((resolve, reject) => 
        db.find(params, (err, result) => {
            if(err) {
                reject(err);
            } else {
                resolve(result);
            }
        })
    )
};

Then, using this promisified db find, your code can be written as

B

Promise.all([
    dbFindPromise(db, { completed: true }).then(tasks => {
        console.log(tasks.length);
        return tasks.length;
    }),
    dbFindPromise(db, { completed: false }).then(tasks => {
        console.log(tasks.length);
        return tasks.length;
    })
]).then(([completed, uncompleted]) => {
    console.log(completed + uncompleted);
});

Alternatively, using jquery Deferred and when - first the "promisified" function

C

function dbFindPromise(db, params) {
    var deferred = $.Deferred();
    db.find(params, (err, result) => {
        if(err) {
            deferred.reject(err);
        } else {
            deferred.resolve(result);
        }
    });
    return deferred.promise();
};

Then to use it:

D

$.when(dbFindPromise(db, { completed: true }).then(tasks => {
        console.log(tasks.length);
        return tasks.length;
    }), dbFindPromise(db, { completed: false }).then(tasks => {
        console.log(tasks.length);
        return tasks.length;
    })
).done((completed, uncompleted) => {
    console.log(completed + uncompleted);
});

So, native promises, code A and B, jquery Promises is code C and D

But, you can use code A with code D or code C with code B - because Promises should behave the same regardless of where they came from (in this case, native vs jquery)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM