Dijkstra's algorithm is slow. (For loops)
As most of the detail needed to workout what is going on, is missing, (See my comment on question) one can only review what one can see.
Your request to resolve laggy code is impossible to address without makes a lot of guesses.
Bugs.
There is no path through the function pathfindLoop that does not call its self. This will cause you problems, however your intent is unclear and the exact nature of the problem depends on your intent.
Unclear awaiting
When you call sleep you await it.
However the recursive call pathfindLoop() is not awaited. It is completely unclear if this is an error only your part (a bug) or deliberate (a problem).
Oh... the infinity of it all
Your function will crash the page as your code does not allow the call stack to pop calls when exiting pathfindLoop
To call pathfindLoop means an infinite list of calls to self.
Guessing your intention one could see this as a way of creating an ongoing polling like system (similar to setInterval or an animation loop using requestAnimationFrame). Wait 10 (what ever's) then process data and repeat.
If this is your intention it is very flawed as you fail to take into account the call stack.
Each call to pathfindLoop adds a new context to the call stack. Each promise creates a new entry on the promise stack.
As the function is async the context can not be removed from the stack until the context of async calls it has made, are resolved. This will never happen and eventually calling pathfindLoop will crash the page, well before that the page will become very unresponsive (laggy).
Maybe this is the lag you mention in your question. Though without further details one can only guess.
General points
Further points noticed when reviewing the code.

Poor naming.

JS convention is not to use snake_case for variable names. It is generally only used in js when defining names in UPPERCASE_SNAKE

Inconsistent use of semicolons.

Odd placement of semicolon. You have a semicolon at the end of an if clause. eg if (foo); {... the semi colon is ignored, but one is left to wonder as to your intent here?

Too heavily reliant on higher scope. Particularly because you mutate pgrids, and realPgrids. This may or may not be bad but again without further information one can only guess.

Unclear use of higher scoped or undefined variables. Is the variable build defined??? Will adding &quot;use strict&quot; to your code cause it to crash??

Unsafe use of for...in loops. In modern JS there really is no reason to use for...in  loops. Rather use for...of  loop
Example of using for of rather than for in. From your code...

for (build in builds) {
    if (dist4(builds[build][1], builds[build][2], res.x, res.y) &lt; GRID_SPREADING.b_col) {
        go = false;
        break;
    }
 }


Assuming builds is an object
  for (const build of Object.values(builds)) {
      if (dist4(build[1], build[2], res.x, res.y) &lt; GRID_SPREADING.b_col) {
          go = false;
          break;
      }
  }

Or assuming builds is an array
  for (const build of builds) {
      if (dist4(build[1], build[2], res.x, res.y) &lt; GRID_SPREADING.b_col) {
          go = false;
          break;
      }
  }

  // OR

  go = builds.every(build =&gt; dist4(build[1], build[2], res.x, res.y) &gt;= GRID_SPREADING.b_col);

ref to Array.every


Rewrite??
I can not fully rewrite your code as I can not code unknown details.
The rewrite will address the call stack problem and assumes pathfindLoop to be akin to a polling function.
&quot;use strict&quot;; // Always use this directive. 

const pathfindLoop = () =&gt; { // do not use async here
    // ... the rest of your code here

    setTimeout(pathfindLoop, 10); // assumes 10 from sleep(10); is ms
}

Refs

strict_mode
setTimeout