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 กับมัน
