3

My code works but with additional parenthesis like myfunction()();. It should execute with single parenthesis just like normal e.g myfunction();.

I'm building console.time(); console.timeEnd(); polyfill for browsers (e.g <IE10) which do not have native built-in. Note: I have bind() polyfill in-case you think <IE10 does not have it.

Here is my code in "polyfill.js file".

(function() {
    'use strict';
    var console=window.console,  timers={};
    
    if (!console.time) {
        
        console.time = function(name) {
            var datenow = Date.now();
            name = name? name: 'default';
            if (timers[name]) {
                console.warn('Timer "'+name+'" already exists.');
            }
            else timers[name] = datenow;
        };
        
        console.timeEnd = function(name) {
            var datenow = Date.now();
            name = name? name: 'default';
            if (!timers[name]) {
                console.warn('Timer "'+name+'" does not exists.');
            }
            else {
                var endt = datenow - timers[name];
                delete timers[name];
                //below is the line where some changes are needed, But I don't know how.
                return window.console.log.bind(window.console, name+ ': ' +endt+ 'ms');
            }
        };
    }
}());

Now in another file "main.js file", when I use console.time(); console.timeEnd();, it should log code-line-number of this file in browser console (not the line-number of polyfill.js file). Of-course it works but notice additional parenthesis "()()" below which is not cool.

console.time();
//any code for performance test goes here.
console.timeEnd()(); //Note here "()()". It should be single "()"

I have consulted these 2 stackoverflow questions, but couldn't come up with the right answer.

I also checked new Error().stack; as an option, but it is also not supported in those browser for which I'm building my polyfill.

Note: If anyone can suggest a solution with eval();, you can. It is also acceptable for me.

samar
  • 135
  • 1
  • 8
  • So, is the problem that `console.log` will show the filename and line number of the location it was *called* from? Because if that's the case, then I don't see how what you want to achieve is possible. A getter could be a solution but I guess those browser don't support getters either. – Felix Kling Sep 26 '21 at 09:05
  • @FelixKling I couldn't understand what you mean. What I want is just `console.timeEnd()();` should execute with single parenthesis like `console.timeEnd();` – samar Sep 26 '21 at 09:08
  • 1
    If you would not use a stone age browser you could also use https://developer.mozilla.org/en-US/docs/Web/API/Performance/now – The Fool Sep 26 '21 at 09:14
  • @TheFool , I want to support all old browsers. Those browsers still have some user-base. I don't want to miss them. – samar Sep 26 '21 at 09:16
  • 1
    Define all old browser. Like IE1 too? Also, Netscape maybe? – The Fool Sep 26 '21 at 09:17
  • @TheFool, hahaha, no brother. I want to support IE6-11, opera-mini & old opera browsers etc. – samar Sep 26 '21 at 09:19
  • Change `return window.console.log.bind(window.console, name+ ': ' +endt+ 'ms');` to `return window.console.log(name+ ': ' +endt+ 'ms');` so you're invoking the log function instead of returning a new bound function. – Sly_cardinal Sep 26 '21 at 12:01
  • @Sly_cardinal , if I do so what you suggested, it will log the line-number of polyfill.js file. But I want it to log the line-number of "main.js file" – samar Sep 26 '21 at 12:07
  • I see, you have three requirements: 1. support old browsers, 2. log the line number where the call was made, and 3. avoid the double brackets `()()`. Unfortunately, for technical reasons, it's not possible to have all three at once, you'll have to compromise on one of them. Either: A. allow `()()` and use your polyfill as-is (✅1, ✅2, ❌3); B. drop support for old browsers and use the `getter` to avoid `()()` (❌1, ✅2, ✅3); C. or don't use `console.log.bind` to avoid `()()` but lose the line number (✅1, ❌2, ✅3). – Sly_cardinal Sep 26 '21 at 12:18
  • @Sly_cardinal , can you give me solution with "getter". I can later use polyfill for getter if a browser don't have support for it. thank you. – samar Sep 26 '21 at 12:28
  • It's the updated answer in the link you have in your question: "A proper wrapper for console.log with correct line numver": https://stackoverflow.com/a/66415531/81723 Getters and `Object.defineProperty()` are only supported down to IE9, it's not possible to polyfill them in earlier browsers. But I think using getters is the best approach given your requirements. – Sly_cardinal Sep 26 '21 at 12:33

1 Answers1

3

There is in fact a function for that called console.trace, which you can read more about in the MDN page. What it does is print the entire stack trace to the line where it has been called from.

So, for example, running the next code:

function firstFunc() {
  secondFunc();
}

function secondFunc() {
  console.trace('I was called here!');
}

console.log('Calling firstFunc:');
firstFunc();

will print out this output in the console:

Calling firstFunc:

I was called here!
secondFunc @ VM141:6
firstFunc @ VM141:2
(anonymous) @ VM141:10 // Internal browser trace

Notice that in the given output, all functions are being called and defined in the Chrome console, hence the @ VM141:. Generally, it prints the file instead of VM. So, had it been located in an index.js file, it would look like this:

Calling firstFunc:

I was called here!
secondFunc @ index.js:8

Compatibility Note

The above method works for any sane browser, and IE11+. That is due to the implementation of console.trace only in IE11. However, per OP's request, I can think of a creative way to support IE10, and that is by using the Error.prototype.stack property. Now, of course, as MDN itself mentions it, it's a non-standard feature that should not be used in production, but neither is supporting IE6.

By creating an Error instance and then printing its stack, you can achieve a similar result.

const sumWithTrace = (num1, num2) => {
  console.log(new Error().stack); // Creating a new error for its stack property
  return num1 + num2;
};

sumWithTrace(1, 5); // returns 6 and prints trace in console
Eldar B.
  • 1,097
  • 9
  • 22
  • IE9 is telling me, `console.trace();` "Object doesn't support property or method 'trace'" – samar Sep 26 '21 at 09:10
  • 1
    why are you using IE9 ? – The Fool Sep 26 '21 at 09:11
  • First of all, I agree with @TheFool, but it makes sense: In the MDN doc that I linked it clearly shows in the compatibility table that `console.trace` is supported only in IE11 and above. – Eldar B. Sep 26 '21 at 09:12
  • I want to support all old browsers. – samar Sep 26 '21 at 09:14
  • First of all, I doubt any of your users need to see a trace log in their console. I suppose this is purely for development, where you probably use far more up-to-date browsers. Second of all, the world-wide usage, and even the usage among all Internet Explorers and Edge browsers, of IE10 and below is under 1%. – Eldar B. Sep 26 '21 at 09:18
  • @samar edited to my best effort – Eldar B. Sep 26 '21 at 09:34
  • right now I'm playing with `new Error().stack` I will come back to your answer if I could come up with what I want. I am very grateful for your effort. thank you. I will also wait in-case some other user come up with a different idea. – samar Sep 26 '21 at 09:40
  • By the way, is your only problem the fact that you need to call the timeEnd twice, or do you try to find a way to print the line number regardless? @samar – Eldar B. Sep 26 '21 at 09:45
  • @EldarB. my only only problem is with calling the `timeEnd()()` twice. It should work with one call like `timeEnd()`. – samar Sep 26 '21 at 09:47
  • @samar Then I just added an answer that solves that problem. I thought your main concern was printing the line. – Eldar B. Sep 26 '21 at 09:52
  • @EldarB. , A solution with `eval();`, is also acceptable for me. – samar Sep 26 '21 at 12:17
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/237521/discussion-between-eldar-b-and-samar). – Eldar B. Sep 26 '21 at 12:17