1

I am trying to find the elapsed time in JavaScript. The most common approach suggested is to use console.time(label) and console.timeEnd(label).

For example, see: https://stackoverflow.com/a/18427652/5192528

This solution works if I try it on the client-side JavaScript, i.e.

console.time('task');

setTimeout(end, 10);

function end() {
  console.timeEnd('task');
}

prints

finish: 11ms

which is the correct time elapsed.

However, when I try the same code in my express app running on Node, I get a different output:

finish: 30.714111328125ms
finish: 31.104ms

That is, console.timeEnd('task') prints both the lines above. So it's printing the start time and end time, which is different from the documentation.

Here's my code and the output in the console.

const express = require("express");

let router = express.Router();

router.get("/", getAllPosts);

async function getAllPosts(req, res, next) {

    console.time('finish');

    setTimeout(end, 10);

    function end() {
        console.timeEnd('finish');
    }

    let posts = [];
    res.render("index", {
        posts,
        isLoggedIn: false
    });
}

// Output in Console (in debug mode):

finish: 15.8291015625ms
finish: 16.218ms

This is the output when I am not in debug mode:

node ./bin/www

express-session deprecated undefined resave option; provide resave option 
app.js:24:3
express-session deprecated undefined saveUninitialized option; provide 
saveUninitialized option app.js:24:3
app started on http://localhost:3000/
cntr = 1
GET / 304 26.882 ms - -
finish: 26.566ms
GET /stylesheets/style.css 304 4.196 ms - -
GET /javascripts/script.js 304 1.367 ms - -
GET /javascripts/file-upload.js 304 2.229 ms - -
GET /favicon.ico 200 3.718 ms - 15086

Note: both the values are printed on console.timeEnd(). I have verified this by stepping through each line, i.e. console.time didn't log anything, and console.timeEnd logged the output in the console. I am on node version 12.16.1.

Why am I getting different results for the same code snippet?

software_writer
  • 3,941
  • 9
  • 38
  • 64
  • 1
    You don't show where exactly this is in Express, but my guess is that you put it in middleware and that middleware is getting hit by both your web page request and by some other request such as favicon or a script file or an image or something like that. So, it's printing twice because your server is getting two requests. If you log `req.url` at the same time, it may reveal why you're getting called twice. – jfriend00 Mar 26 '20 at 05:36
  • I have edited the question to show the sample code and the output. I believe it's not getting two requests, as while debugging, the breakpoints only get hit once, but I could be wrong. – software_writer Mar 27 '20 at 01:50
  • Please don't post code as images. It makes it impossible to copy that code into our own test app or into an answer, thus making it difficult for people to write you a good answer. Code should be pasted as text and formatted appropriately. – jfriend00 Mar 27 '20 at 01:54
  • Sounds good, I will update the question. Thanks for the tip. – software_writer Mar 27 '20 at 01:56

4 Answers4

2

Looks like this is an issue with using Visual Studio Code in the Debug mode.

https://github.com/Microsoft/vscode/issues/38376

and something I have to live with till VS Code team decides to do something about it.

I have opened a new issue on VS Code's Github repository that details the steps to reproduce this behavior.

software_writer
  • 3,941
  • 9
  • 38
  • 64
0

Well, there has to be something else going on in parts of your code that you don't show us because if I make your code into a working app by just adding three more lines at the end like this and changing the res.render() to a res.send() so we don't have to have a template and template engine configured (for simplicity of the example):

const express = require("express");

let router = express.Router();

router.get("/", getAllPosts);

async function getAllPosts(req, res, next) {

    console.time('finish');

    setTimeout(end, 10);

    function end() {
        console.timeEnd('finish');
    }

    let posts = [];
    res.send("hello");
}

const app = express();
app.use(router);
app.listen(80);

And, then I request http://localhost in the browser, this is all I see in the server console:

finish: 11.708ms

There's just one of them.

So, something else in the code you don't show us is apparently causing your issue. I am wondering what's in index.html? Is there by any chance an Ajax call to / or any other resource requests in that HTML file?

Apparently, there is something else that is making another request to your server. I'd suggest you instrument that route like I show below to just prove that the route is getting called twice:

const express = require("express");

let router = express.Router();

router.get("/", getAllPosts);

let cntr = 1;                                        // add this
async function getAllPosts(req, res, next) {

    console.log(`cntr = ${cntr++}`);                 // add this

    console.time('finish');

    setTimeout(end, 10);

    function end() {
        console.timeEnd('finish');
    }

    let posts = [];
    res.send("hello");
}

const app = express();
app.use(router);
app.listen(80);
jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thanks for the detailed answer. I tried your code snippet, and the counter only printed once. So the method is definitely getting executed once per request. However, I noticed that if I launch the site without debugging, I get a 304 redirect status code, just before the log prints the time. Maybe that has anything to do with this? I have updated my question to add the complete log output. Please let me know what you think. – software_writer Mar 27 '20 at 03:36
  • @AkshayKhot - I don't know what you mean by the new log. There's only one "finish" line there. The 304 status has to do with caching. If you cleared your browser cache or disabled caching, you wouldn't get that. – jfriend00 Mar 27 '20 at 03:41
  • Right, I reloaded the page with devtools open, and it gave the same output, with 200 code. – software_writer Mar 27 '20 at 03:50
  • The problem turns out to be in the `www` file that `express-generator` set up for me. I still don't understand why it's happening, though. I have posted an answer explaining the cause. – software_writer Mar 27 '20 at 04:39
0

After removing all my extraneous code line by line, I finally figured out the cause, without the understanding. If anyone can explain why it's happening, I will mark it as the answer.

The problem turns out to be in my bin/www file, which looks like this:

#!/usr/bin/env node

var app = require("../app");

app.listen(3000);

I set up the app using express-generator, which use bin\www JavaScript file to configure the app.

// app.js

var express = require("express");

var app = express();

app.use("/", function getAllPosts(req, res, next) {

  console.time('finish');

  setTimeout(end, 10);

  function end() {
      console.timeEnd('finish');
  }

  res.send("hello");
});

module.exports = app;

If I run the app without using www, console.timeEnd() works as expected.

For example, this code works fine:

var express = require("express");

var app = express();

app.use("/", function getAllPosts(req, res, next) {

  console.time('finish');

  setTimeout(end, 10);

  function end() {
      console.timeEnd('finish');
  }

  res.send("hello");
});

app.listen(3000);
software_writer
  • 3,941
  • 9
  • 38
  • 64
  • My only guess is that `var app = require("../app");` isn't loading the right `app.js`. Otherwise, there's no difference. – jfriend00 Mar 27 '20 at 18:46
  • I believe it's loading the correct app.js, as all my routers and other variables defined in `app.js` work fine. – software_writer Mar 27 '20 at 18:50
0

I was able to demonstrate both of your outcomes from the answer you posted.

The issue is that you're using .use() instead of .get() in your route definition:

app.use("/", function getAllPosts(req, res, next) {...}

When you use app.use("/", ...), that will match ALL possible routes. So, when you first do the www version, you will get two requests from the browser:

/
/favicon.ico

Both of those will match app.use("/", ...). .use() matches any route that starts with what you specify.


Then, when you remove the www file from the equation, you're still executing the exact same code EXCEPT that the browser has cached the fact that there's no favicon.ico so it doesn't request it. If you do a shift reload on the single file version, it shows the same problem because the browser again requests the favicon.ico and you get two requests.


Change this:

app.use("/", function getAllPosts(req, res, next) {...}

to:

app.get("/", function getAllPosts(req, res, next) {...}

and this particular problem goes away in the code you show in your 2nd answer. I don't know why you changed this route to app.use() because you used to have it as app.get(). This was clear to me when I added this:

console.log("in route", req.url);

to the start of the route handler. That's where I clearly saw the /favicon.ico request causing the extra output.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • I changed from `app.use()` to `app.get()` and still got the log twice(which is what I had originally, as you mention). However, I noticed that it's only happened in the debug mode. I am not seeing the log twice when I start the app using `npm start` (doesn't matter if it's `use` or `get`). It only prints it once. That's really strange as I did see it twice last night, but I could be wrong. – software_writer Mar 28 '20 at 01:16
  • I also notice this behavior in debug mode with `app.get/post()`even if I remove the favicon entirely. – software_writer Mar 28 '20 at 01:31
  • Figured it out, finally. Looks like a side-effect of running VS Code in debug mode. Please see my new answer. Thank you for taking your time to look into this. – software_writer Mar 28 '20 at 01:41