How to use a rotary encoder on NodeMCU with Arduino code?
Different RotaryEncoders work in different ways. Mine connects the two outputs sequentially to the Gnd or + inputs, depending on the rotation direction. The resultant phase changes need to be detected and decoded by the processor.
I took your code and ran it on a LoLin NodeMCU using my 5-pin RotaryEncoder.
I connected (NodeMCU to RotaryEncoder):

D0 to Clk;
D3 to DT;
GND to GND; and
3V to +.

I ran the code, and it worked: the printed value went up when I rotated it in one direction, and down when it rotated in the other. The &quot;bounce&quot; was terrible though - getting just a single increment or decrement for one &quot;detent&quot; was difficult; I typically got 2-4.
Because of my encoder, I was able to remove the two digitalWrite(..., HIGH); lines and it continued to work. Perhaps that's what your problem is? Did you connect the + input? You mention the two switch pins: perhaps there's only one switch pin, that connects to the Gnd pin?

EDIT: The code!
So I went away and wrote a RotaryEncoder polling library, rather than the interrupt code that the original question was based on. The idea is that you can poll a rotary encoder (relatively) infrequently, and stil &quot;catch&quot; the transitions as it rotates. Of course this won't work if you poll it too slowly - your mileage may vary!
But here are three files:

The header and library source for the RotaryEncoder module; and
An example usage of the module.

RotaryEncoder.h:
//
// RotaryEncoder.h
//
// This library manages a Keyes KY-040 Rotary Encoder by sampling the
// appropriate pins when requested. It is NOT interrupt driven, so you'll need
// to sample often.
//
// The encoder has five pins in a 0.1&quot; row, so you can directly plug it into
// an Arduino's data-pin sockets. The sequence of pins matches the order of
// parameters in the constructor - use ascending (or descending) numbers for
// ease.
//
// If you pass in NoPin for gnd, vcc, or sw (the switch), then that parameter
// is ignored. You'll need to organise those pins yourself! Of course, NoPin is
// not valid for dt or clk.
//

#ifndef RotaryEncoder_h
#define RotaryEncoder_h

class RotaryEncoder {

public: // Typedefs and enums

   typedef byte Pin;

   typedef signed char OptPin;
   
   enum Pins : OptPin {
      NoPin = -1
   }; // Pins

public: // Methods

   // Define which pins to use for the various functions.
   // If Optional Pins are &quot;NoPin&quot;, then they won't be initialised
   RotaryEncoder(OptPin gnd, OptPin vcc, OptPin sw, Pin dt, Pin clk);

   // Start RotaryEncoder with optional maxBias (call Rebias() periodically)
   void Begin(byte maxBias=1);

   // Returns true if switch is currently pressed
   bool Switch() const;

   // Returns 0 for no change, +ve for clockwise, -ve for counter-clockwise
   int Get();
   
   // Call this periodically to reduce the bias
   void Rebias(int delta=1);

private: // Variables

   const OptPin gndPin;

   const OptPin vccPin;

   const OptPin swPin;

   const Pin dtPin;

   const Pin clkPin;
   
   byte maxBias;
   
   byte bias;

   bool clk;

   bool dt;

}; // RotaryEncoder

#endif // RotaryEncoder_h

RotaryEncoder.cpp:
//
// RotaryEncoder.cpp
//

#include &lt;Arduino.h&gt;
#include &quot;RotaryEncoder.h&quot;

RotaryEncoder::RotaryEncoder(OptPin gnd, OptPin vcc, OptPin sw, Pin dt, Pin clk) :
               gndPin(gnd),
               vccPin(vcc),
               swPin(sw),
               dtPin(dt),
               clkPin(clk),
               maxBias(1),
               bias(1),
               clk(false),
               dt(false) {
} // RotaryEncoder::RotaryEncoder(gnd, vcc, sw, dt, clk)

void RotaryEncoder::Begin(byte maxBias) {
   this-&gt;maxBias = maxBias;
   if (gndPin!=NoPin) {
      pinMode(gndPin, OUTPUT); // Let's power the device,
      digitalWrite(gndPin, LOW);  // Power -ve with 0
   } // if
   if (vccPin!=NoPin) {
      pinMode(vccPin, OUTPUT); // ,with both - and +
      digitalWrite(vccPin, HIGH); // Power +ve with 1
   } // if
   if (swPin!=NoPin) {
      pinMode(swPin, INPUT_PULLUP); // They pushed it!
   } // if
   pinMode(dtPin,  INPUT); // One half
   pinMode(clkPin, INPUT); // The other half
} // RotaryEncoder::Begin(maxBias)

bool RotaryEncoder::Switch() const {
   return swPin!=NoPin ?
          digitalRead(swPin)==LOW :
          false;
} // RotaryEncoder::Switch()

int RotaryEncoder::Get() {
   bool clkNew = digitalRead(clkPin);
   if (clk!=clkNew) {
      clk = clkNew; // Clock's changed; sample data
      bool dtNew = digitalRead(dtPin);
      if (dt!=dtNew) {
         dt = dtNew; // Data's changed; remember it!
         if (clk) {  // Only pay attention to Clk Low-High
            int temp = bias;
            bias = maxBias;
            if (dt) {
               return -temp;
            } // if
            else {
               return +temp;
            } // else
         } // if
      } // if
   } // if
   return 0;
} // RotaryEncoder::Get()

void RotaryEncoder::Rebias(int delta) {
   if (bias&lt;=1) {
       return;
   } // if
   bias -= bias&gt;delta ? delta : bias-1;
} // RotaryEncoder::Rebias()

RotaryBlinker.ino:
//
// RotaryBlinker
//
// This example changes how fast the built-in LED blinks by using the
// RotaryEncoder library.
// It starts with an intermediate value (80h).
// * If you rotate it left, it slows down (then it jumps to the fastest).
// * If you rotate it right, it speeds up (then it jumps to the slowest).
// The jumps are because there is no logic to handle wrap-around - an exercise
// for the reader!
//
// Also note that a bias feature has been included. The faster you turn the knob, the
// exponentially quicker the rate changes. This is done by setting a fast rate on
// every detent, then when the millisecond has changed it re-biases the knob lower.
//
// To handle the knob correctly, it needs to INCREASE the time interval when
// dialling LOWER - hence you'll see a negative number in the code.
//
// It also checks for the switch. If it's pressed, it simply turns the LED full on.
//

#include &lt;RotaryEncoder.h&gt;

// Choose pins that are convenient for the RotaryEncoder's pins
#if defined(ESP8266)

const byte LED = D5;                   // No built-in LED! Choose... this one!
const unsigned baud = 115200;
const RotaryEncoder::OptPin GND = -1; // Use GND pin
const RotaryEncoder::OptPin VCC = -1; // Use V+ pin
const RotaryEncoder::OptPin SW  =  D4; // Switch
const RotaryEncoder::Pin    DT  =  D3; // Data
const RotaryEncoder::Pin    CLK =  D2; // Clock

#elif defined(ADifferentBoard) // Put the board's definition here

// And then change these assignments
const byte LED = LED_BUILTIN;
const unsigned baud = 57600;
const RotaryEncoder::OptPin GND =  8; // Need 0V
const RotaryEncoder::OptPin VCC =  9; // Need +V
const RotaryEncoder::OptPin SW  = 10; // Switch
const RotaryEncoder::Pin    DT  = 11; // Data
const RotaryEncoder::Pin    CLK = 12; // Clock

#else // Arduino Uno default

const byte LED = LED_BUILTIN;
const unsigned baud = 57600;
const RotaryEncoder::OptPin GND =  8; // Need 0V
const RotaryEncoder::OptPin VCC =  9; // Need +V
const RotaryEncoder::OptPin SW  = 10; // Switch
const RotaryEncoder::Pin    DT  = 11; // Data
const RotaryEncoder::Pin    CLK = 12; // Clock

#endif // Boards

// Tell library which pin does what. Note Optional Pins can be -1
RotaryEncoder encoder(GND, VCC, SW, DT, CLK);

// Setup the board for these definitions
void setup() {
    Serial.begin(baud);
    pinMode(LED, OUTPUT); // Want to see it working

    encoder.Begin(10); // Start, with a re-bias of 10
} // setup()

bool ledON = false;  // Current LED state
byte repeat = 0x80;  // How quickly to restart, in ms
byte count = repeat; // Count down 'til next time!

unsigned last = 0;   // Last time millis() was recorded

void loop() {
    // Have switch override pulsing - turn it hard ON
    if (encoder.Switch()) { // Hard override!
        ledON = false; // Pretend LED is now OFF
        digitalWrite(LED, HIGH);
    } // if
    else {
        int value = encoder.Get(); // Returns positive for clockwise turn
        repeat += -value;   // We want to INCREASE time to slow down blinking
        if (value!=0) {     // Did it change?
            Serial.print(value);    // Print latest value
            Serial.print('=');
            Serial.println(repeat); // Print new result
        } // if
    } // else

    // Is it time to blink the LED again?
    unsigned latest = millis();
    if (last!=latest) {
        last = latest;
        encoder.Rebias();    // Re-bias encoder, to decelerate rotation
        if (--count==0) {    // Reached zero yet?
            ledON = !ledON;  // Yes! Toggle LED
            digitalWrite(LED, ledON ? HIGH : LOW);
            count = repeat;  // Count for next time
       } // if
    } // if
} // loop()