ค้นหาเว็บไซต์

จาวาสคริปต์ - การใช้งานล็อกแบบเรียกซ้ำ


ฉันได้สร้างมิกซินที่สามารถซิงโครไนซ์ได้ ซึ่งให้ฟังก์ชัน synchronized:

const lock = Symbol('Synchronizable lock');
const queue = Symbol('Synchronizable queue');

export class Synchronizable {
  private [lock] = false;
  private [queue]: Array<() => void> = [];

  public async synchronized<T>(fn: () => Promise<T>): Promise<T> {
    while (true) {
      if (this[lock]) await new Promise(resolve => this[queue].push(resolve));
      else {
        this[lock] = true;
        try {
          return await fn();
        } finally {
          this[lock] = false;
          const tmp = this[queue];
          this[queue] = [];
          tmp.forEach(e => e());
        }
      }
    }
  }
}

แต่ตัวล็อกไม่ใช่แบบเรียกซ้ำได้ การล็อกวัตถุเมื่อถูกล็อกอยู่แล้วจะทำให้เกิดการล็อกตาย:

const c = new Synchronizable();
await c.synchronized(() => c.synchronized(async () => void 0));

วิธีการใช้งานล็อกแบบเรียกซ้ำคืออะไร?

โค้ดทั้งหมดถูกอัปโหลดไปยัง GitHub พร้อมกับชุดทดสอบ

ความคิดแรก

เหมือนกับภาษาอื่น ๆ ทุกภาษา บันทึก thread-id ปัจจุบันเมื่อทำการล็อก แล้วเปรียบเทียบ thread-id ที่บันทึกกับ thread-id ปัจจุบัน หากตรงกันก็ดำเนินการต่อ

แต่จาวาสคริปต์ไม่ได้ให้รหัสเธรด และการเลื่อนการปิดทับก็ไม่ได้สร้างรหัสใหม่

ความคิดที่สอง

ติดตามสแตกของการเรียก ใช้หาการเรียกล็อกอื่นใดภายในสแตก ตรวจสอบว่ามันเป็นล็อกเดียวกันหรือไม่

ปัญหาคือ stack trace อาจจะไม่ตาม callback เช่น setTimeout ดังนั้นมันจะไม่สามารถตรวจจับการล็อกก่อน callback ได้

คำตอบ #1

ฉันพบว่ามันสามารถทำได้โดยใช้ Zone.js ตามวิธีแรก ซึ่ง Zone.js ให้วิธีในการกำหนดตัวแปรเฉพาะเธรด