简体   繁体   中英

Node.js callback, wait for function to end

I'm trying to send an ajax request that retrieves a list of file names from an ftp server. Retrieving the files is not a problem, but when I pass my ajax request (click on the button in my index.ejs file), it renders the view before finishing getting all the files (the files variable in res.render is empty). I've tried using async parallel but the execution either gets stuck in the searchFiles function or renders the view before the function execution. Any thoughts ? (I guess I do my callback the wrong way,I just can't figure how).

In my server.js file :

var Files = require('./prototypes/files.js');
var files, searchedFiles;

app.get('/search', function (req, res) {
    files = new Files();
    files.searchFiles(req.query.t, function(searchedFiles) {
        console.log(searchedFiles);
        res.render('index', {files: searchedFiles});
    });
});

In my files.js file :

function Files() {
}

Files.prototype.searchFiles = function(searchedText, callback) {
    var connectionProperties = {
        host: "host",
        user: "username",
        password: "password"
    }
    var folders = ["", "0-9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X-Z"];
    var Client = require('ftp'); 
    var c = new Client();
    var files = {};    
    c.on('ready', function () {
        folders.forEach(function(folder) {
            c.list("/pools/A/A0/Movies/Films/" + folder, function (err, list) {
                if (err) throw err;
                list.forEach(function (element, index, array) {
                    if (element.name.match("(mkv|avi|mp4|mov)$") && (element.name.toLowerCase().indexOf(searchedText.toLowerCase()) > -1)) {
                        console.log(element.name);
                        files[element.name] = element.size;
                    }
                });
            });
        });
    });
    c.connect(connectionProperties);
    callback(files);
}

module.exports = Files

In my index.ejs file I've got this block and script:

<div id="container">
    <% if (typeof files !== 'undefined' && files ) { for (file in files) { %>
        <p><%= file + " ----- " + files[file] %></p>
    <% }} %>
</div>
<button onclick="getFiles(); return false; %>">LOL</button>
<script>
    function getFiles() {
        searchedText = 'wild'; // wild is used as an example here
        if (searchedText != "") {
            $.ajax({
                type: 'GET',
                cache: false,
                url: "http://localhost:8080/search?t=" + searchedText,
                success: function(data) {
                    $('#container').html(data);
                }
            });
        }
    }
</script>

I found out how to work it out with async, thx to @RayonDabre

I had to check if the loops were all done before doing my callback function using async (the foreach loop in javascript is blocking so async has to be used).

The code is now :

var i = 0;
c.on('ready', function () {
    folders.forEach(function(folder) {
        c.list("/pools/A/A0/Movies/Films/" + folder, function (err, list) {
            if (err) throw err;
                var j = 0;
                async.forEach(list, function (element, index, array) {
                if (element.name.match("(mkv|avi|mp4|mov)$") && (element.name.toLowerCase().indexOf(searchedText.toLowerCase()) > -1)) {
                    files[element.name] = element.size;
                }
                if ((i == folders.length - 1) && (j == list.length - 1)) {
                    callback(files);
                }
                j++;
            });
            i++;
        });
    });
});`

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