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

javascript - จะตรวจสอบโปรแกรมว่าฟังก์ชันเป็น async ได้อย่างไร?


ฉันกำลังพยายามที่จะ override (monkey patch) ฟังก์ชัน it() ของเฟรมเวิร์ก Jasmine และในกระบวนการนี้ ฉันต้องการทราบว่าฟังก์ชันที่ถูกส่งเป็นอาร์กิวเมนต์ตัวที่สองให้กับฟังก์ชัน it() เป็นประเภท async หรือไม่ ฉันพยายามใช้ instanceof Promise เพราะฟังก์ชัน async ทุกตัวจะคืนค่าเป็น promise แต่ก็ไม่เคยประเมินผลเป็น true และไม่เคยเข้าไปในบล็อก if ในโค้ดดังต่อไปนี้ ฉันได้ลองล็อกฟังก์ชันทั้งหมดไปที่คอนโซลแล้ว และพบว่าฟังก์ชัน async() ทั้งหมดมีชนิดค่าที่คืนค่าเป็น tslib_1.awaiter(บางอาร์กิวเมนต์..)

นี่คือสิ่งที่ฉันมี:

let newIt = jasmine.getEnv().it;
jasmine.getEnv().it = function(...args): jasmine.Spec {
  // do something.
 if(args[1] instanceOf Promise) {
   debugger; // never comes in here.
   // catch error.
 }
 return newIt.apply(this, arguments);
}

ฉันกำลังทำอะไรผิดอยู่หรือเปล่า? ใครสามารถช่วยชี้แนวทางที่ถูกต้องให้ฉันได้ไหม?

ขอบคุณ

แก้ไข: สมมติว่าฉันมีสเปคตัวอย่างสองอันดังนี้ อันหนึ่งเป็นแบบอะซิงโครนัสและอีกอันเป็นแบบซิงโครนัส:

การทดสอบแบบอะซิงค์:

const exp = () => {
            return new Promise((resolve, reject) => {
                setTimeout(() => {
                    resolve(1);
                }, 500);
            });
        };

 it('asyncTest', async () => {
      expect(await exp()).toEqual(1);
  }, 600);

ประสานเวลา :

it('testNon', () => {
     expect(true).toBe(true);
 });

คำตอบ #1

นี่คือปัญหา XY ตามที่ได้ชี้ให้เห็นในคำตอบนี้ โดยปกติไม่จำเป็นต้องตรวจสอบว่ามันเป็นฟังก์ชัน async หรือไม่เพราะสิ่งนี้ไม่สำคัญ ฟังก์ชัน async เป็นเพียงฟังก์ชันที่ส่งคืน promise ทั้ง () => Promise.resolve() และ async() => {} ควรได้รับการพิจารณาในลักษณะเดียวกัน

สิ่งนี้ได้รับการยืนยันจากข้อเท็จจริงที่ว่ามันเป็นไปไม่ได้ที่จะสามารถแยกความแตกต่างระหว่าง async กับฟังก์ชันปกติในโค้ด TypeScript ที่ถูกแปลง - ทั้งสองเป็นเพียงฟังก์ชันปกติ

args[1] instanceOf Promise นั้นไม่ถูกต้อง เพราะฟังก์ชันจะไม่ใช่อ็อบเจกต์ของ Promise การปรับแต่งแบบ monkey-patching ส่วนใหญ่จะทำในลักษณะนี้ (ซึ่งไม่เฉพาะเจาะจงกับ Jasmine หรือกรณีนี้):

let newIt = jasmine.getEnv().it;
jasmine.getEnv().it = function(...args): jasmine.Spec {
  const fn = args[1];
  let newFn;
  if (fn.length > 0) {
    // async spec with done param
    newFn = function (done) {
      const result = fn.call(this, done);
      if(result instanceOf Promise)
      // or even better,
      // if(result && typeof result.then === 'function')
        debugger;
      return result;
    }
  } else {
    newFn = function () {
      const result = fn.call(this);
      if(result instanceOf Promise)
        debugger;          
      return result;
    }
  }

  args[1] = newFn;
  return newIt.apply(this, args);;
}

นี่คือผลลัพธ์ฟังก์ชันทดสอบ result ที่ควรถูกตรวจสอบว่าเป็นอินสแตนซ์ของ Promise (หรือต้องตรวจสอบว่ามี thenable หรือไม่)

คำตอบ #2

นี่ไม่ทำงานเพราะฟังก์ชันแบบอะซิงค์จะส่งกลับค่าเป็นพรอมิสอยู่เสมอ แต่ตัวฟังก์ชันเองไม่ใช่พรอมิส

คำตอบง่าย ๆ คือ ดูที่ตัวสร้างของฟังก์ชันที่เกี่ยวข้อง (แต่ฉันจะอธิบายว่าทำไมคุณไม่ควรหลังจากนี้):

const isAsync = func.constructor.name === 'AsyncFunction';

ปัญหาของแนวทางนี้คือฟังก์ชันแบบ async ไม่ได้ถูกออกแบบให้แตกต่างจากฟังก์ชันปกติที่คืนค่าเป็น promise จริง ๆ จะดีกว่าถ้าใช้ Promise.resolve เพื่อเปลี่ยนผลลัพธ์จากการเรียกฟังก์ชันใด ๆ ให้เป็น Promise แล้วใช้ await กับมัน