Skip to content
20 / 33

Как Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ цикличСская Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡ‚ΡŒ Π² модулях?


ΠŸΠΎΠ»Π½Ρ‹ΠΉ ΠΎΡ‚Π²Π΅Ρ‚

Как Π΄Π²ΠΈΠΆΠΎΠΊ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅Ρ‚ Ρ†ΠΈΠΊΠ» Π² ESM:

JavaScript
// a.js
import { b } from "./b.js";
console.log("a.js Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½, b =", b);
export const a = "A";

// b.js
import { a } from "./a.js";
console.log("b.js Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½, a =", a);
export const b = "B";

ΠŸΠΎΡ€ΡΠ΄ΠΎΠΊ выполнСния (Ссли Ρ‚ΠΎΡ‡ΠΊΠ° Π²Ρ…ΠΎΠ΄Π° β€” a.js):

  1. Π”Π²ΠΈΠΆΠΎΠΊ Π½Π°Ρ‡ΠΈΠ½Π°Π΅Ρ‚ ΠΏΠ°Ρ€ΡΠΈΡ‚ΡŒ a.js, Π²ΠΈΠ΄ΠΈΡ‚ import ΠΈΠ· b.js
  2. ΠŸΠ΅Ρ€Π΅Ρ…ΠΎΠ΄ΠΈΡ‚ ΠΊ парсингу b.js
  3. b.js ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚ a ΠΈΠ· a.js, Π½ΠΎ a.js Π΅Ρ‰Ρ‘ Π½Π΅ выполнился
  4. a сущСствуСт ΠΊΠ°ΠΊ привязка, Π½ΠΎ Π΅Ρ‰Ρ‘ Π½Π΅ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Π½Π°
  5. b.js выполняСтся: console.log("b.js Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½, a =", undefined)
  6. b инициализируСтся Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ "B"
  7. Π’ΠΎΠ·Π²Ρ€Π°Ρ‚ ΠΊ a.js: console.log("a.js Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½, b =", "B")
  8. a инициализируСтся Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ΠΌ "A"

Π’ CommonJS ситуация ΠΏΠΎΡ…ΠΎΠΆΠ°, Π½ΠΎ ΠΌΠ΅Ρ…Π°Π½ΠΈΠ·ΠΌ Π΄Ρ€ΡƒΠ³ΠΎΠΉ:

JavaScript
// a.js (CJS)
const { b } = require("./b");
console.log("a.js Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½, b =", b);
module.exports = { a: "A" };

// b.js (CJS)
const { a } = require("./a");
console.log("b.js Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½, a =", a); // undefined β€” a.js Π΅Ρ‰Ρ‘ Π½Π΅ экспортировал
module.exports = { b: "B" };

ΠŸΠΎΡ‡Π΅ΠΌΡƒ ESM справляСтся Π»ΡƒΡ‡ΡˆΠ΅ β€” live bindings:

JavaScript
// counter.js (ESM)
import { increment as incFromB } from "./b-counter.js";

export let count = 0;

export function increment() {
  count++;
}

// b-counter.js (ESM)
import { count } from "./counter.js";

export function increment() {
  // count β€” Тивая ссылка, Π²ΠΈΠ΄ΠΈΡ‚ Π°ΠΊΡ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠ΅ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅
  console.log("b Π²ΠΈΠ΄ΠΈΡ‚ count =", count);
}

// Π”Π°ΠΆΠ΅ ΠΏΡ€ΠΈ цикличСских зависимостях live binding обновляСтся ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎ

Π Π΅Π°Π»ΡŒΠ½Ρ‹Π΅ кСйсы

Как Π²ΠΎΠ·Π½ΠΈΠΊΠ°Π΅Ρ‚ Ρ†ΠΈΠΊΠ» Π² Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΌ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π΅:

JavaScript
// ❌ Випичная ΠΏΡ€ΠΎΠ±Π»Π΅ΠΌΠ°
// user.js
import { Order } from "./order.js";

export class User {
  getOrders() {
    return Order.findByUser(this.id);
  }
}

// order.js
import { User } from "./user.js";

export class Order {
  getUser() {
    return User.findById(this.userId);
  }
}

// User ΠΈ Order ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΡŽΡ‚ Π΄Ρ€ΡƒΠ³ Π΄Ρ€ΡƒΠ³Π° β€” Ρ†ΠΈΠΊΠ»!

Как ΠΈΡΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ β€” вынСсти ΠΎΠ±Ρ‰Π΅Π΅ Π² Ρ‚Ρ€Π΅Ρ‚ΠΈΠΉ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ:

JavaScript
// βœ… РСшСниС 1: Ρ‚Ρ€Π΅Ρ‚ΠΈΠΉ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ-посрСдник
// repository.js
import { User } from "./user.js";
import { Order } from "./order.js";

export function getOrdersForUser(userId) {
  return Order.findByUser(userId);
}

export function getUserForOrder(order) {
  return User.findById(order.userId);
}

// βœ… РСшСниС 2: Π»Π΅Π½ΠΈΠ²Ρ‹ΠΉ ΠΈΠΌΠΏΠΎΡ€Ρ‚
// user.js

export class User {
  async getOrders() {
    const { Order } = await import("./order.js");
    return Order.findByUser(this.id);
  }
}

РСзюмС

ЦикличСскиС зависимости тСхничСски Ρ€Π°Π±ΠΎΡ‚Π°ΡŽΡ‚ Π² ΠΎΠ±Π΅ΠΈΡ… ΠΌΠΎΠ΄ΡƒΠ»ΡŒΠ½Ρ‹Ρ… систСмах, Π½ΠΎ часто приводят ΠΊ Π½Π΅ΠΎΠΆΠΈΠ΄Π°Π½Π½Ρ‹ΠΌ undefined. ESM справляСтся Π»ΡƒΡ‡ΡˆΠ΅ благодаря live bindings, Π½ΠΎ это Π½Π΅ ΠΏΠΎΠ²ΠΎΠ΄ ΠΌΠΈΡ€ΠΈΡ‚ΡŒΡΡ с Ρ†ΠΈΠΊΠ»Π°ΠΌΠΈ. Π›ΡƒΡ‡ΡˆΠΈΠΉ ΠΏΠΎΠ΄Ρ…ΠΎΠ΄ β€” Ρ€Π΅Ρ„Π°ΠΊΡ‚ΠΎΡ€ΠΈΠ½Π³: вынСсти ΠΎΠ±Ρ‰ΡƒΡŽ Π»ΠΎΠ³ΠΈΠΊΡƒ Π² ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹ΠΉ ΠΌΠΎΠ΄ΡƒΠ»ΡŒ ΠΈΠ»ΠΈ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π»Π΅Π½ΠΈΠ²Ρ‹ΠΉ import().

Как Ρ€Π°Π±ΠΎΡ‚Π°Π΅Ρ‚ цикличСская Π·Π°Π²ΠΈΡΠΈΠΌΠΎΡΡ‚ΡŒ Π² модулях? | JScriptiser