0
\$\begingroup\$

I'm trying to optimize my JavaScript code to be a short as possible (this is just for fun). Any thoughts would be appreciated!

Basically, the script automatically clicks an "I'm still here" button on a website. To do that, it checks every 100 ms for the prompt (class .dialog-box), and if it sees it, it waits between 1 and 5 seconds and then clicks the "I'm here" button (class .here-button).

function delay(n){
    return new Promise(function(resolve){
        setTimeout(resolve,n);
    });
}

let p=x => document.querySelector(x);

(async function() {
    while(true){
        await delay(100);
        if(x=p(".dialog-box")) {
            x.style.visibility = "hidden";
            await delay(1e3+4e3*Math.random());
            console.log(new Date().toLocaleTimeString() + ": Clicked");
            p(".here-button").click();
        }
    }
})();

I'm going to run it through a minifier as well, but I'm curious if there are ways to make the code shorter?

Thanks in advance!

\$\endgroup\$
5
  • 1
    \$\begingroup\$ If you really want it as short as possible, you want Code Golf rather than Code Review. \$\endgroup\$ Mar 9, 2022 at 8:32
  • \$\begingroup\$ Thanks, Toby! I wasn't aware that existed (I was sent here from Stack Overflow)--good to know! \$\endgroup\$
    – mmmmm12345
    Mar 9, 2022 at 23:14
  • \$\begingroup\$ What is the performance angle about the problem at hand? \$\endgroup\$
    – greybeard
    Mar 10, 2022 at 8:39
  • \$\begingroup\$ @greybeard I wasn't clear in my description, but I'd love to make the code efficient as well--my brute force method of looking for the dialog box ten times a second seems wasteful. \$\endgroup\$
    – mmmmm12345
    Mar 12, 2022 at 1:04
  • \$\begingroup\$ Requests for minification are out-of-scope for this site. \$\endgroup\$
    – Mast
    Dec 14, 2022 at 9:26

2 Answers 2

0
\$\begingroup\$

Nice using scientific notation to shave a character off those milliseconds.

Instead of using async and promises, you could just run an anonymous interval every 100ms. Each time the interval runs, it checks for the .dialog-box element. If it finds it, it stops searching until after it waits for 1–5 seconds and clicks the .here-button element—then resumes searching.

A human-friendly version

let searching = 1, getElement = selector => document.querySelector(selector)
setInterval(() => {
  if (searching && getElement('.dialog-box')) {
    searching = 0
    setTimeout(() => {
      getElement('.here-button').click()
      searching = 1
    }, 1e3 + 4e3 * Math.random())
  }
}, 100)

Shortened variable names

let s = 1, e = s => document.querySelector(s)
setInterval(() => {
  if (s && e('.dialog-box')) {
    s = 0
    setTimeout(() => {
      e('.here-button').click()
      s = 1
    }, 1e3 + 4e3 * Math.random())
  }
}, 100)

Minified (160 characters)

let s=1,e=s=>document.querySelector(s);setInterval(()=>{if(s&&e('.dialog-box')){s=0;setTimeout(()=>{e('.here-button').click();s=1},1e3+4e3*Math.random())}},100)
\$\endgroup\$
5
  • \$\begingroup\$ Beautiful, thank you! And even if I add back the lines to hide the dialog box and log to console with the time, I'm still dozens characters shaved off! \$\endgroup\$
    – mmmmm12345
    Mar 9, 2022 at 3:12
  • 1
    \$\begingroup\$ I'm not crazy about using numbers as booleans, among other practices here. searching = 0 should be searching = false. That's unacceptable even in C nowadays. If your goal is shortness, then this seems halfway in, halfway out because there are plenty of other ways to shorten things, so I'd suggest going all-readability and let the minifier handle the rest. I also prefer the async/promise approach from the original; it's so nice that it's been made standard in Node 17. \$\endgroup\$
    – ggorlen
    Mar 9, 2022 at 3:23
  • \$\begingroup\$ Interesting, thank you! I didn't realize the promise thing was so widely adopted. \$\endgroup\$
    – mmmmm12345
    Mar 9, 2022 at 13:00
  • \$\begingroup\$ @ggorlen The question asks to make the code shorter, for fun. Not to make it more performant or readable. \$\endgroup\$
    – Sean
    Mar 9, 2022 at 13:38
  • \$\begingroup\$ Yes, that's clearly your/OP's intent, but then why not drop let, use & instead of &&, and _ instead of ()? I'm not much of a code golfer but these seem like low-hanging fruit. \$\endgroup\$
    – ggorlen
    Mar 9, 2022 at 14:50
3
\$\begingroup\$

What's the benefit of trying to minify or shorten the code in situ? As Sean showed, you can always plop it into a minifier, but while coding, shorthand like

let p=x => document.querySelector(x);

is probably not too helpful to your future self that might want to maintain or debug the script. Sometimes I see this aliased using the $ variable (when jQuery isn't otherwise being used:

const $ = x => document.querySelector(x);
const $$ = x => document.querySelectorAll(x);

(note I've used const instead of the weaker let; we don't want to accidentally reassign this variable)

Style nitpicks

I'd suggest using an autoformatter like prettier or the internal Stack Snippets editor.

  • function delay(n){ -> function delay(ms) {
  • setTimeout(resolve,n); -> setTimeout(resolve, ms);
  • while(true){ -> while (true) { or for (;;) {
  • 1000 is much clearer than 1e3 to me -- it's not worth shaving a character.

Bigger issues

The line:

if(x=p(".dialog-box")) {

creates a global variable x attached to the window which can potentially cause a bug. If you put "use strict"; at the top of your script, you'll get a nice error protecting you from yourself. As a rule of thumb, don't do assignments in conditions like this unless you really know what you're doing and are sure it's going to read more cleanly than moving it to a separate line.

If you're running this as a bookmarklet or userscript on another site, I would put all of the code into the IIFE closure so to avoid clashing with globals.

Secondly, do you need to poll like this, or can you use a MutationObserver? Observing mutations means you won't need to burn cycles continually to keep checking the predicate; the code will only run when there's a DOM mutation on the watched subtree. Without seeing a representative sample of the page this works on, it's hard to say much more though.

It's probably not applicable here, but requestAnimationFrame will give you a tighter polling loop and is often a useful tool for these userscript situations.

A quick rewrite

(async () => {
  "use strict";

  const delay = ms => new Promise(res => setTimeout(res, ms));
  const $ = x => document.querySelector(x);

  for (;;) {
    await delay(100);
    const elem = $(".dialog-box");

    if (elem) {
      elem.style.visibility = "hidden";
      await delay(1000 + 4000 * Math.random());
      console.log(new Date().toLocaleTimeString() + ": Clicked");
      $(".here-button").click();
    }
  }
})();
<div class="dialog-box"></div>
<button class="here-button"></button>

\$\endgroup\$
3
  • \$\begingroup\$ Super thorough and thoughtful--thank you! This is just a script I was playing with to get used to JavaScript, and so I was trying to figure out inefficiencies in my code. I'll take a look at MutationObserver as well, as I think you're right that that would run better! \$\endgroup\$
    – mmmmm12345
    Mar 9, 2022 at 12:59
  • \$\begingroup\$ I've never seen an expressionless for loop without a break statement. Surely a while loop would be better for your readability directive if you're critiquing ones and zeroes being used for booleans. Also, the request was to make it shorter, which it doesn't seem like you've done. \$\endgroup\$
    – Sean
    Mar 9, 2022 at 13:33
  • 1
    \$\begingroup\$ @Sean From what I've seen, the site is primarily about code review, not code golf, so it seems OK to review a golfing request with a normal code review. As I mentioned in the other thread, OP only seems to be half-attempting to golf, as does your answer, so I erred on the side of not-golf. From my experience, for (;;) is roughly as common an idiom as a while (true) for creating infinite loops, but I'd be just fine with while if you prefer -- it's not really integral to my response. \$\endgroup\$
    – ggorlen
    Mar 9, 2022 at 14:45

Not the answer you're looking for? Browse other questions tagged or ask your own question.