2

I'm having trouble adjusting to the async-first nature of node / js / typescript. This intent of this little function should be pretty clear: it takes a database and returns an array of courses that are listed in that database.

The problem is that the return statement gets run before any of the database operations have run, and I get an empty list. When I set a breakpoint inside the database each loop, I can see that the rows are being found and that courses are being put into ret one by one, but these courses never become visible in the scope where courseList() was called.

const courseList = (database: sqlite3.Database): Course[] => {
    let ret = new Array<Course>();

    database.serialize();
    database.each("select ID, Title from Course", (err: Error, row: Object) => {
        ret.push(new Course(
            row.ID,
            row.Title
        ))
    })

    return ret;
}

Suggestions?

The calling code just wants to print information about courses. For example:

let courses = courseList(db);
console.log(courses.length); // logs 0, even though the db contains courses
10
  • Nothing special about NodeJS here, just higher order functions, specifically callbacks. Can you show the calling code? Commented Apr 17, 2017 at 21:07
  • 1
    Check this: stackoverflow.com/questions/39106668/… Commented Apr 17, 2017 at 22:05
  • @AluanHaddad Added some example calling code. Commented Apr 17, 2017 at 23:23
  • @NiloCK you have a bug somewhere else or code you are omitting. The function indeed works. See here where I have your code but with a mocked database jsbin.com/rixivofeke/1/edit?js,console Yes, there is a race condition, but the function returns a value. It does not behave as you describe. Commented Apr 17, 2017 at 23:34
  • @AluanHaddad I think I muddled that. If you're VSCode handy, this repo: www.github.com/nilock/lynda-copy-course can be built / launched to demonstrate the behavior. See lines 9-12 of /bin/lynda-copy-course.ts, and lines 20-35, and 66-86 of /src/index.ts Commented Apr 18, 2017 at 0:05

1 Answer 1

2

database.each takes a complete callback. Use that to resume e.g.

const courseList = (database: sqlite3.Database, complete): Course[] => {
    let ret = new Array<Course>();

    database.serialize();
    database.each("select ID, Title from Course", (err: Error, row: Object) => {
        ret.push(new Course(
            row.ID,
            row.Title
        ))
    }, complete);

    return ret;
}
let courses = courseList(db, () => {
    console.log(courses.length); 
});

More

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.