ECMAScript7 async/await พฤติกรรมที่ไม่สอดคล้องกัน ขึ้นอยู่กับว่าใช้วงเล็บในฟังก์ชันลูกศรหรือไม่

ฉันพบพฤติกรรมที่ไม่สอดคล้องกันใน Google Chrome 60.0.3112.78 (รุ่นอย่างเป็นทางการ) (64 บิต) เมื่อใช้ ES6+ async/await สมัยใหม่ ขึ้นอยู่กับว่าฉันใช้วงเล็บในฟังก์ชันลูกศรที่ส่งคืน สัญญา. สิ่งเดียวกันนี้เกิดขึ้นใน Node.js ฉันมีปัญหาในการทำความเข้าใจว่าทำไม

ฉันเข้าใจว่านี่ไม่ใช่วิธีการใช้ฟังก์ชัน sleep() แต่เป็นวิธีที่ง่ายที่สุดในการสาธิต พิจารณาตัวอย่างโค้ดต่อไปนี้

function sleep(ms = 0) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

(async () => {
  console.log('a');
  await sleep(5000);
  console.log('b');
})()

ตามที่คาดไว้ การดำเนินการนี้จะเขียน a ไปยังคอนโซล รอ 5 วินาที จากนั้นเขียน b ไปยังคอนโซล


สัญกรณ์ที่สั้นลงโดยใช้ฟังก์ชันลูกศรเพื่อส่งคืน สัญญา

const sleep = ms => { return new Promise(resolve => setTimeout(resolve, ms)) }

(async () => {
  console.log('a');
  await sleep(5000);
  console.log('b');
})()

ตามที่คาดไว้รหัสนี้ทำงานเหมือนกัน a และ b ถูกเขียนไปยังคอนโซลโดยมีช่วงเวลา 5000 มิลลิวินาที อยู่ระหว่างนั้น


รหัสต่อไปนี้ใช้งานไม่ได้ ข้อแตกต่างเพียงอย่างเดียวคือฉันไม่ได้ใส่การส่งคืนของ Promise ในวงเล็บในบรรทัดแรก

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

(async () => {
  console.log('a');
  await sleep(5000);
  console.log('b');
})()

ในกรณีนี้ การรอโหมดสลีปจะไม่ทำงาน ที่จริงแล้วรหัสนี้ไม่ได้ทำอะไรเลยเลย จะไม่บันทึกสิ่งใดลงในคอนโซล ไม่ใช่ a และไม่ใช่ b

ฉันคิดว่าตัวเองมีประสบการณ์พอสมควร แต่ตอนนี้ฉันยังไม่เข้าใจสิ่งนี้ เหตุใดวงเล็บจึงมีความสำคัญในกรณีนี้ ค่าที่ส่งคืนจะเหมือนกันใช่ไหม? และทำไมแม้แต่อักขระ a ถึงไม่ได้รับการบันทึกคอนโซล?

ใครก็ได้โปรดอธิบายให้ฉันฟังอย่างชัดเจนและเจาะจงว่าทำไมถึงเป็นเช่นนี้ นี่เป็นแมลงหรือฉันแค่ต้องการนอนเอง?

ขอบคุณมาก.


person Jochem Stoel    schedule 04.08.2017    source แหล่งที่มา
comment
@4castle หากคุณอ้างถึง คำตอบนี้ ฉันแนะนำให้ใช้ฟังก์ชัน การประกาศ แทน (function sleep(ms) { return … }) ซึ่งไม่จำเป็นต้องมีอัฒภาคเลย :-)   -  person Bergi    schedule 05.08.2017


คำตอบ (1)


สิ่งสำคัญคือเครื่องหมายอัฒภาคหลังฟังก์ชันลูกศร เขียน

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
//                                                                 ^

และมันจะได้ผล โปรดสังเกตว่าบรรทัดถัดไปขึ้นต้นด้วย ( ซึ่งเป็นความต่อเนื่องทางไวยากรณ์ที่ถูกต้อง ดังนั้น ASI จะไม่กระโดดเข้ามา รหัสของคุณ ถูกแยกวิเคราะห์และตีความว่าเป็น

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))(async () => { … })()

แต่ฟังก์ชัน sleep ไม่เคยถูกเรียกใช้

person Bergi    schedule 04.08.2017
comment
@Matthew เป็นเช่นนั้น แต่ถ้าคุณต้องการละเว้นอัฒภาคและปล่อยให้พวกมันถูกแทรกโดยอัตโนมัติทุกครั้งที่เป็นไปได้ คุณจะ ต้องวางไว้ที่ เริ่มต้น ของทุกบรรทัดที่ขึ้นต้นด้วย (, [, /, +, - หรือ ` - person Bergi; 05.08.2017
comment
ฮ่าฮ่า ใช่แล้ว แต่ความไม่ชัดเจนของข้อผิดพลาดนี้ทำให้ฉันซาบซึ้งกับการกดแป้นพิมพ์เพิ่มเติม - person Wolfie; 05.08.2017
comment
ขอบคุณ! คุณพูดถูก ฉันไม่อยากจะเชื่อเลยว่าฉันพลาดไป วุ้ย จริงๆ แล้วฉันไม่เคยใช้เซมิโคลอนอย่างเคร่งครัด เว้นแต่ว่าจะไม่มีทางอื่นและเชื่อว่าคุณสามารถระบุนักพัฒนาที่ดีได้ด้วยนิสัยนี้ แต่ฉันลำเอียง ขอบคุณอีกครั้ง! :) - person Jochem Stoel; 05.08.2017
comment
เหตุผลก็คือ การใส่เครื่องหมายอัฒภาคมักจะง่ายกว่าการพยายามจดจำว่าจำเป็นต้องใช้หรือไม่จำเป็นเมื่อใด ดังนั้นจึงลดความเป็นไปได้ที่จะเกิดข้อผิดพลาด - person Jaime; 05.08.2017
comment
@JochemStoel ฉันคงเดาได้ว่าถ้าคุณละเว้นมันในฟังก์ชัน async เช่นกัน :-) - person Bergi; 05.08.2017
comment
@Jaime ฉันไม่เห็นด้วย ต้องจำทุกครั้งว่าจำเป็นต้องใช้เซมิโคลอนหรือไม่ ช่วยให้คุณมีสมาธิในฐานะนักพัฒนา มันบังคับให้คุณเข้าไปอยู่ในนั้น ไม่มีอะไรในระบบนำร่องอัตโนมัติ - person Jochem Stoel; 06.08.2017
comment
@JochemStoel ฉันคิดว่าคุณเสียเวลาอย่างน้อยหนึ่งชั่วโมงในการพยายามคิดว่าเหตุใดรหัสของคุณจึงไม่ทำงานตามที่คาดไว้ การแทรกอัฒภาคอัตโนมัติ (ASI) ถือเป็นคุณลักษณะหนึ่งของ JavaScript ที่เป็นที่ถกเถียงกันมาก เราควรปฏิบัติต่อ ASI ราวกับว่าไม่มีอยู่จริง - person Jaime; 07.08.2017
comment
@Jaime เราไม่ควรลืมอัฒภาค ไม่ว่าจะอยู่ที่ท้ายทุกบรรทัดหรือจุดเริ่มต้นของทุกบรรทัด (ที่ขึ้นต้นด้วยวงเล็บ) ก็ไม่สำคัญ มันเป็นความชอบส่วนตัวโดยสิ้นเชิง และเมื่อคุณคุ้นเคยกับวิธีใดวิธีหนึ่งแล้ว คุณก็จะสามารถระบุจุดหายไปได้อย่างง่ายดาย หรือปล่อยให้ลินเดอร์ทำ ทั้งสองสไตล์ก็มีกฎเกณฑ์เหมือนกัน - person Bergi; 07.08.2017
comment
@Bergi คุณช่วยอัปเดตคำตอบของคุณเพื่อรวมโค้ดของ OP ด้วยเครื่องหมายอัฒภาคนำหน้า IIFE หรือไม่ - person Mihail Malostanidis; 03.03.2018
comment
@MihailMalostanidis ไม่ไม่รวมส่วนที่ได้รับการแก้ไขเพียงพอใช่ไหม - person Bergi; 03.03.2018