มีเหตุผลใดบ้างที่จะใช้ XMLHttpRequest แบบซิงโครนัส


88

ดูเหมือนว่าทุกคนส่วนใหญ่จะส่งคำขอแบบอะซิงโครนัสกับ XMLHttpRequest แต่เห็นได้ชัดว่ามีความสามารถในการร้องขอแบบซิงโครนัสบ่งชี้ว่าอาจมีเหตุผลที่ถูกต้องในการทำเช่นนั้น แล้วเหตุผลที่ถูกต้องนั่นคืออะไร?


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

3
การโทรแบบซิงโครนัสปิดกั้นเบราว์เซอร์ซึ่งนำไปสู่ประสบการณ์การใช้งานที่แย่มาก ดังนั้นคำถามของฉัน ฉันคิดไม่ออกว่าจะใช้เหตุผลอะไรดี
Darrell Brogdon

2
คำตอบกึ่งจริงจัง: อาจเพียงเพื่อเติมเต็มบทที่มาก่อนคำขอแบบอะซิงโครนัสในหนังสือ JavaScript ที่คุณกำลังอ่าน
Ben James

โดยส่วนตัวแล้วฉันต้องการใช้ ajax ที่เป็นซิงโครนัสเพื่อตัดการโทรหลายครั้งไปยังฟังก์ชันเซิร์ฟเวอร์โดยไม่ต้องเขียนคำขอสำหรับการโทรแต่ละครั้ง
Paul Ishak

รันโค้ดในเครื่องโดยเฉพาะอย่างยิ่งสำหรับเฟรมเวิร์กและเครื่องมือภายใน
user2800679

คำตอบ:


26

ฉันคิดว่าอาจเป็นที่นิยมมากขึ้นเมื่อมาตรฐาน HTML 5 ก้าวหน้าขึ้น หากเว็บแอปพลิเคชันสามารถเข้าถึงผู้ปฏิบัติงานบนเว็บได้ฉันสามารถคาดการณ์ล่วงหน้าว่านักพัฒนาโดยใช้ผู้ปฏิบัติงานบนเว็บโดยเฉพาะเพื่อส่งคำขอแบบซิงโครนัสตามที่โจนาธานกล่าวเพื่อให้แน่ใจว่ามีคำขอหนึ่งรายการเกิดขึ้นก่อนหน้าอื่น ด้วยสถานการณ์ปัจจุบันของเธรดเดียวจึงเป็นการออกแบบที่น้อยกว่าในอุดมคติเนื่องจากบล็อกจนกว่าคำขอจะเสร็จสมบูรณ์


16
ฉันคิดว่าเขาหมายถึง 'Web Workers'
evilpie

ผมคิดว่าจุดกลั่น ใน UI เธรดสร้างเธรดหรืองาน async ประเภทต่างๆ หากอยู่ในเธรดแล้วให้ใช้ซิงโครไนซ์ในกรณีส่วนใหญ่ เธรดเป็น "บล็อกที่เป็นมิตร" มากกว่ามาก
HaMMeReD

นี่เป็นคำตอบเก่า แต่ความคิดเห็นนี้ใช้ได้กับแม้กระทั่งก่อนหน้านั้น HTML5 เบราว์เซอร์มีให้สำหรับ 2 เธรดสำหรับการร้องขอ ฉันเขียนสคริปต์พูลการเชื่อมต่อเพื่อใช้ทั้งสองอย่างเพราะถึงแม้จะมีการร้องขอ async ด้วยการเชื่อมต่อเดียวคุณก็สามารถผูกเบราว์เซอร์ การใช้ทั้งสองอย่างช่วยให้สามารถผลัก / ดึงข้อมูลผ่านสายได้มากขึ้น แต่ iirc ฉันคิดว่าคำขอซิงค์ยังคงเชื่อมโยงกับเบราว์เซอร์
vol7ron

Firefox (และเป็นไปได้ว่าเบราว์เซอร์ที่ไม่ใช่ IE ทั้งหมด) ไม่รองรับ async XHR timeOut HTML5 WebWorkers รองรับการหมดเวลา ดังนั้นคุณอาจต้องการตัดการร้องขอ XHR การซิงค์ไปยัง WebWorker ด้วยการหมดเวลาเพื่อใช้งาน XHR แบบ async ที่มีลักษณะการหมดเวลา
Dmitry Kaigorodov

1
-1. นี่ไม่ใช่คำตอบมากนักและการสนทนาทั้งหมดเกี่ยวกับเธรดเป็นเพียงความสับสนในเรื่อง คำตอบด้านล่างของ Sami นั้นดีกว่ามาก
Stijn de Witt

30

XHR แบบซิงโครนัสมีประโยชน์สำหรับการบันทึกข้อมูลผู้ใช้ หากคุณจัดการbeforeunloadเหตุการณ์คุณสามารถอัปโหลดข้อมูลไปยังเซิร์ฟเวอร์ได้ในขณะที่ผู้ใช้ปิดเพจ

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


4
แก้ไข: ฉันรู้ว่าคุณเพิ่งทิ้ง txt จากผู้ใช้ HN ที่ขี้เกียจ แต่ใช้เวลาเพียงเล็กน้อยในการใช้ถ้อยคำมันเป็นที่ชื่นชมที่นี่ใน SO
Frank Krueger

แต่จริงๆแล้วนี่เป็นเหตุผลเดียวที่ฉันได้เห็นจนถึงตอนนี้
Stijn de Witt

@ แฟรงค์ครูเกอร์ HN คืออะไร?
ดักลาสจัดขึ้น

1
@DouglasHeld เว็บไซต์ชื่อว่า Hacker News ที่
news.ycombinator.com

13

อัปเดต:

คำใบ้ด้านล่าง - แต่ไม่ประสบความสำเร็จในการส่ง - เนื่องจากการมาของการจัดการคำขอแบบอะซิงโครนัสที่ดีขึ้นจึงไม่มีเหตุผลที่จะใช้คำขอแบบซิงโครนัสเว้นแต่จะตั้งใจบล็อกผู้ใช้ไม่ให้ทำอะไรจนกว่าคำขอจะเสร็จสมบูรณ์ - ฟังดูเป็นอันตราย: )

แม้ว่าสิ่งนี้อาจฟังดูไม่ดี แต่อาจมีบางครั้งที่สำคัญที่คำขอ (หรือชุดคำขอ) เกิดขึ้นก่อนที่ผู้ใช้จะออกจากหน้าหรือก่อนที่จะดำเนินการ - บล็อกการเรียกใช้รหัสอื่น ๆ (เช่นการป้องกันปุ่มย้อนกลับ) อาจ อาจลดข้อผิดพลาด / การบำรุงรักษาสำหรับระบบที่ออกแบบมาไม่ดี ที่กล่าวว่าฉันไม่เคยเห็นมันในป่าและเน้นว่าควรหลีกเลี่ยง

ไลบรารีเช่นเดียวกับสัญญาแสร้งทำเป็นซิงโครไนซ์โดยการผูกมัดกระบวนการผ่านการเรียกกลับ สิ่งนี้เหมาะกับความต้องการในการพัฒนาส่วนใหญ่ซึ่งความต้องการคือการสั่งซื้อเหตุการณ์ที่ไม่ปิดกั้นซึ่งทำให้เบราว์เซอร์สามารถรักษาการตอบสนองของผู้ใช้ได้ (UX ที่ดี)

ตามที่ระบุไว้ในเอกสาร Mozillaมีหลายกรณีที่คุณต้องใช้คำขอแบบซิงโครนัส อย่างไรก็ตามรายการนี้ยังเป็นวิธีแก้ปัญหาที่ใช้บีคอน (ไม่มีใน IE / Safari) สำหรับกรณีดังกล่าว แม้ว่าจะเป็นการทดลอง แต่หากได้รับการยอมรับตามมาตรฐานก็สามารถใส่ตะปูลงในโลงศพแบบซิงโครนัสได้


คุณต้องการทำการโทรแบบซิงโครนัสในการประมวลผลแบบธุรกรรมใด ๆ หรือที่ใดก็ตามที่จำเป็นต้องมีลำดับการทำงาน

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

อีกเหตุผลหนึ่งก็คือเมื่อทำงานกับ WebService โดยเฉพาะอย่างยิ่งเมื่อทำการคำนวณบนเซิร์ฟเวอร์

ตัวอย่าง:เซิร์ฟเวอร์มีตัวแปรที่มีค่า 1

 Step (1) Perform Update: add 1 to variable
 Step (2) Perform Update: set variable to the power of 3
 End Value: variable equals 8

ถ้าขั้นที่ (2) เกิดขึ้นก่อนค่าสุดท้ายคือ 2 ไม่ใช่ 8 ดังนั้นจึงจำเป็นต้องมีลำดับการดำเนินการและการซิงโครไนซ์


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

ดังที่คนอื่น ๆ กล่าวไว้ว่ามันจะผูกเบราว์เซอร์ของคุณดังนั้นอย่าอยู่ห่างจากที่คุณทำได้

อย่างไรก็ตามแทนที่จะเป็นการโทรแบบซิงโครนัสผู้ใช้มักต้องการหยุดเหตุการณ์ที่กำลังโหลดอยู่แล้วดำเนินการอื่น ๆ ในลักษณะนี้คือการซิงโครไนซ์เนื่องจากเหตุการณ์แรกจะหยุดก่อนที่เหตุการณ์ที่สองจะเริ่มขึ้น ในการดำเนินการนี้ให้ใช้วิธี abort () บนอ็อบเจ็กต์การเชื่อมต่อ xml


1
ฉันคิดว่านี่น่าจะเป็นคำตอบที่แท้จริง

3
@ แซ็ค: นี่เป็นตัวอย่างที่ดี แต่คุณอาจทำได้เช่นเดียวกันกับการโทรแบบอะซิงโครนัสขึ้นอยู่กับเหตุการณ์ที่เรียกมัน
vol7ron

3
+1 มีกรณีที่ถูกต้องที่เงื่อนไขการแข่งขันเชิงตรรกะอาจเป็นผลมาจากการร้องขอเซิร์ฟเวอร์แบบอะซิงโครนัส ... อย่างไรก็ตามการแก้ปัญหาไม่จำเป็นต้องเป็นซิงโครไนซ์ เว้นแต่คำขอของคุณจะได้รับการจัดการจาก Web Worker จะเป็นการดีกว่าหากเขียนเลเยอร์การขนส่งที่จะให้หมายเลขคำขอจากนั้นตรวจสอบให้แน่ใจว่าการดำเนินการได้รับการจัดการตามลำดับของรหัสคำขอ
Roy Tinker

3
-1 การประมวลผลธุรกรรมเป็นตัวอย่างที่สมบูรณ์แบบที่คุณต้องใช้การรับประกันว่าสิ่งนั้นล้มเหลวหรือประสบความสำเร็จเพียงเพราะคำสั่งซิงโครนัสไม่ได้หมายความว่าคำขอแรกสำเร็จ ... คุณต้องพึ่งพาการตอบสนองที่บอกคุณเช่นนั้น ในตัวอย่างนี้คุณจะทำคำขอที่สองเท่านั้นจากภายในผลการจัดการการร้องขอแรก - ซึ่งในกรณีที่พวกเขาทั้งสองอาจรวมทั้งจะ async
Mathew

2
@Mathew: นั่นจะเป็นจริงก็ต่อเมื่อกระบวนการทำธุรกรรมของคุณขึ้นอยู่กับผลของการกระทำก่อนหน้านั้น หากคุณมีปุ่มที่สร้างวัตถุใหม่ (ดึงมาจากเซิร์ฟเวอร์) ในเพจของคุณ หากเป็นแบบอะซิงโครนัสผู้ใช้อาจคลิกหลายครั้งและส่งคืนวัตถุจำนวนมาก การโทรแบบซิงโครนัสจะป้องกันไม่ให้สิ่งนั้นและอนุญาตให้สร้างอ็อบเจ็กต์ใหม่อื่นหลังจากเสร็จสิ้นครั้งแรกเท่านั้นไม่ว่าจะผิดพลาดหรือไม่ก็ตาม โปรดใส่ใจกับคำพูดฉันทำเหมือนธุรกรรมและไม่ได้ทำธุรกรรมตามวัตถุประสงค์
vol7ron

8

ฉันจะบอกว่าหากคุณพิจารณาบล็อกเบราว์เซอร์ของผู้ใช้ในขณะที่คำขอเสร็จสมบูรณ์แล้วให้ใช้คำขอแบบซิงโครนัส

หากการทำให้เป็นอนุกรมของคำขอเป็นเป้าหมายของคุณคุณสามารถทำได้โดยใช้คำขอ async โดยให้การเรียกกลับ onComplete ของคำขอก่อนหน้าของคุณเริ่มต้นในบรรทัดถัดไป


1
อืมฉันจะเพิ่มหน้าต่างบานเลื่อนลงไปมิฉะนั้นคุณจะเสียเวลาไปกลับสำหรับแต่ละคำขอโดยทั่วไป
Stephan Eggermont

8

มีหลายกรณีในโลกแห่งความเป็นจริงที่การบล็อก UI เป็นพฤติกรรมที่ต้องการ

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

ในโหมดซิงโครนัสตรรกะนั้นง่ายการบล็อกที่ผู้ใช้พบนั้นสั้นมากและไม่มีปัญหา

ในโหมด async ผู้ใช้อาจเปลี่ยนค่าของฟิลด์อื่น ๆ ในขณะที่กำลังตรวจสอบค่าเริ่มต้น การเปลี่ยนแปลงเหล่านี้จะทริกเกอร์การเรียก xmlhttp อื่นด้วยค่าจากฟิลด์เริ่มต้นที่ยังไม่ได้รับการตรวจสอบ จะเกิดอะไรขึ้นหากการตรวจสอบความถูกต้องเบื้องต้นล้มเหลว ระเบียบบริสุทธิ์ หากโหมดซิงค์เลิกใช้งานและไม่ได้รับอนุญาตตรรกะของแอปพลิเคชันจะกลายเป็นฝันร้ายที่ต้องจัดการ โดยทั่วไปจะต้องเขียนแอปพลิเคชันใหม่เพื่อจัดการการล็อก (เช่นปิดใช้งานรายการอื่น ๆ ในระหว่างกระบวนการตรวจสอบความถูกต้อง) ความซับซ้อนของโค้ดเพิ่มขึ้นอย่างมาก หากไม่ทำเช่นนั้นอาจนำไปสู่ความล้มเหลวของตรรกะและข้อมูลเสียหายในที่สุด

โดยทั่วไปคำถามคืออะไรคือประสบการณ์ UI ที่ไม่ถูกบล็อกหรือความเสี่ยงต่อการเสียหายของข้อมูล คำตอบควรอยู่กับผู้พัฒนาแอปพลิเคชันไม่ใช่ W3C


1
ฉันคิดว่าคุณกำลังรวบรวมแนวคิดในการบล็อกการโต้ตอบของผู้ใช้กับการบล็อกเธรดของเบราว์เซอร์ มีวิธีง่ายๆเป็นพันล้านวิธีในการป้องกันไม่ให้ผู้ใช้โต้ตอบกับเอนทิตีใด ๆ (ฟิลด์แบบฟอร์ม ฯลฯ ) ในระหว่างการเรียกแบบ async ที่ไม่ต้องบล็อกเธรดเบราว์เซอร์ เมื่อด้ายคือการปิดกั้นมีไม่สามารถใด ๆการประมวลผลเชิงตรรกะใด ๆ และนั่นเป็นเพียงสถานการณ์ที่เลวร้ายที่จะอยู่ใน; มันสร้างปัญหา / ปัญหาที่อาจเกิดขึ้นมากมายซึ่งแทบจะไม่สามารถแก้ไขได้มากกว่าที่จะแก้ได้
Luke Chavers

6

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

รากฐานความคิดนั้นขยายออกไปจากคำตอบของ vol7ron ขั้นตอนการทำธุรกรรมเป็นช่วงเวลาเดียวที่ควรทำคำขอแบบซิงโครนัส ในกรณีอื่น ๆ ส่วนใหญ่การโทรแบบอะซิงโครนัสเป็นทางเลือกที่ดีกว่าซึ่งหลังจากการโทร DOM จะได้รับการอัปเดตตามความจำเป็น ในหลาย ๆ กรณีเช่นระบบที่ใช้ผู้ใช้คุณอาจมีคุณลักษณะบางอย่างที่ล็อกไว้สำหรับ "ผู้ใช้ที่ไม่ได้รับอนุญาต" จนกว่าจะมีการลงชื่อเข้าใช้คุณลักษณะเหล่านี้หลังจากการโทรแบบอะซิงโครนัสจะถูกปลดล็อกผ่านขั้นตอนการอัปเดต DOM

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


ความจริงที่ว่าการกระทำขึ้นอยู่กับผลลัพธ์ของการกระทำอื่นจึงไม่มีเหตุผลที่จะดำเนินการอื่นพร้อมกัน เฉพาะในกรณีที่ต้องประมวลผลผลลัพธ์ของการดำเนินการบางอย่างก่อนที่ฟังก์ชันการโทรจะสิ้นสุดคุณจำเป็นต้องมีการโทรแบบซิงโครนัส
Stijn de Witt

5

ในปี 2015 แอป JavaScript บนเดสก์ท็อปกำลังเป็นที่นิยมมากขึ้น โดยปกติแล้วในแอพเหล่านั้นเมื่อโหลดไฟล์ในเครื่อง (และโหลดโดยใช้ XHR เป็นตัวเลือกที่ใช้ได้อย่างสมบูรณ์แบบ) ความเร็วในการโหลดนั้นเร็วมากจนมีจุดที่ซับซ้อนเกินไปเล็กน้อยที่จะทำให้โค้ดทับซ้อนกับ async แน่นอนว่าอาจมีบางกรณีที่ async เป็นวิธีที่จะไป (ขอเนื้อหาจากอินเทอร์เน็ตโหลดไฟล์ขนาดใหญ่จริงๆหรือไฟล์จำนวนมากในชุดเดียว) แต่มิฉะนั้นการซิงค์จะทำงานได้ดี (และใช้งานง่ายกว่ามาก) .


นี่เป็นสถานการณ์ที่ฉันพบตัวเองในปี 2020 ฉันมีแอปเดสก์ท็อปที่แสดง UI ผ่าน HTTP เพื่อให้คุณสามารถเข้าถึงได้จากเบราว์เซอร์ที่ทำงานบนเครื่องภายในหรือแม้กระทั่งผ่านเครือข่าย ในสถานการณ์เหล่านี้เครือข่ายมีความรวดเร็วและเชื่อถือได้ดังนั้นการร้องขอ XHR แบบซิงโครนัสจึงเป็นวิธีที่ดีในการทำให้โค้ดเป็นเรื่องง่าย คนส่วนใหญ่ไม่ทราบว่าคำขอ async XHR นั้นเหมือนกับการใช้เธรดและอาจทำให้เกิดความซับซ้อนมากขึ้นโดยมีโอกาสเกิดข้อบกพร่องมากมาย
Eric Mutta

4

jQuery ใช้ AJAX แบบซิงโครนัสภายในภายใต้สถานการณ์บางอย่าง เมื่อแทรก HTML ที่มีสคริปต์เบราว์เซอร์จะไม่เรียกใช้งาน ต้องดำเนินการสคริปต์ด้วยตนเอง สคริปต์เหล่านี้อาจแนบตัวจัดการคลิก สมมติว่าผู้ใช้คลิกที่องค์ประกอบก่อนที่จะแนบตัวจัดการและหน้าจะไม่ทำงานตามที่ตั้งใจไว้ ดังนั้นเพื่อป้องกันสภาวะการแข่งขันจะใช้ AJAX แบบซิงโครนัสเพื่อดึงสคริปต์เหล่านั้น เนื่องจาก AJAX แบบซิงโครนัสบล็อกทุกอย่างได้อย่างมีประสิทธิภาพจึงมั่นใจได้ว่าสคริปต์และเหตุการณ์จะดำเนินการตามลำดับที่ถูกต้อง


3

เหตุผล:

สมมติว่าคุณมีแอปพลิเคชัน ajax ที่ต้องทำ http ครึ่งโหลเพื่อโหลดข้อมูลต่างๆจากเซิร์ฟเวอร์ก่อนที่ผู้ใช้จะสามารถโต้ตอบใด ๆ ได้

เห็นได้ชัดว่าคุณต้องการให้สิ่งนี้ถูกกระตุ้นจาก onload

การโทรแบบซิงโครนัสทำงานได้ดีมากสำหรับสิ่งนี้โดยไม่ต้องเพิ่มความซับซ้อนให้กับโค้ด มันง่ายและตรงไปตรงมา

ข้อเสียเปรียบ:

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

ทางเลือก?

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

อย่างไรก็ตามดูเหมือนว่าการรับซิงโครนัสจะถูกลบหรือ จำกัด จากเบราว์เซอร์ล่าสุดอยู่ดี ฉันไม่แน่ใจว่าเป็นเพราะใครบางคนตัดสินใจว่าพวกเขาแย่เสมอไปหรือถ้าผู้เขียนเบราว์เซอร์สับสนกับ WC Working Draft ในหัวข้อนี้

http://www.w3.org/TR/2012/WD-XMLHttpRequest-20120117/#the-open- วิธีการทำให้ดูเหมือน (ดูหัวข้อ 4.7.3) คุณไม่ได้รับอนุญาตให้ตั้งค่าการหมดเวลาเมื่อใช้โหมดบล็อก . ดูเหมือนว่าจะใช้งานง่ายสำหรับฉัน: เมื่อใดก็ตามที่มีการบล็อก IO การตั้งค่าระยะหมดเวลาที่เหมาะสมอย่างสุภาพดังนั้นเหตุใดจึงอนุญาตให้บล็อก io แต่ไม่ใช้ระยะหมดเวลาที่ระบุ

ความเห็นของฉันคือการบล็อก IO มีบทบาทสำคัญในบางสถานการณ์ แต่ต้องดำเนินการอย่างถูกต้อง แม้ว่าแท็บเบราว์เซอร์หรือหน้าต่างหนึ่งจะไม่สามารถล็อคแท็บหรือหน้าต่างอื่น ๆ ทั้งหมดได้ แต่นั่นก็เป็นข้อบกพร่องในการออกแบบเบราว์เซอร์ ความอัปยศที่เกิดจากความอัปยศ แต่เป็นที่ยอมรับอย่างสมบูรณ์ในบางกรณีที่แท็บหรือหน้าต่างแต่ละรายการจะไม่ตอบสนองเป็นเวลาสองถึงสามวินาที (เช่นการใช้การบล็อก IO / HTTP GET) ในบางสถานการณ์ - ตัวอย่างเช่นในการโหลดหน้าเว็บอาจมีข้อมูลจำนวนมาก จำเป็นต้องมีก่อนที่จะทำอะไรต่อไป บางครั้งการใช้รหัสบล็อกอย่างถูกต้องเป็นวิธีที่สะอาดที่สุด

แน่นอนว่าฟังก์ชันเทียบเท่าในกรณีนี้สามารถรับได้โดยใช้ http แบบอะซิงโครนัส แต่ต้องมีรูทีนโง่ ๆ แบบไหน

ฉันเดาว่าฉันจะลองทำอะไรตามบรรทัดเหล่านี้:

ในการโหลดเอกสารให้ดำเนินการดังต่อไปนี้: 1: ตั้งค่าตัวแปรแฟล็ก "เสร็จสิ้น" ส่วนกลาง 6 ตัวแปรเริ่มต้นเป็น 0 2: ดำเนินการรับพื้นหลังทั้ง 6 รายการ (สมมติว่าลำดับไม่สำคัญ)

จากนั้นการเรียกกลับที่สมบูรณ์สำหรับ http ทั้ง 6 รายการจะตั้งค่าแฟล็ก "เสร็จสิ้น" ตามลำดับ นอกจากนี้การโทรกลับแต่ละครั้งจะตรวจสอบแฟล็กอื่น ๆ ทั้งหมดเพื่อดูว่า HTTP ทั้ง 6 ได้รับเสร็จสมบูรณ์หรือไม่ การโทรกลับครั้งสุดท้ายที่จะทำให้เสร็จสมบูรณ์เมื่อเห็นว่าคนอื่น ๆ ทำเสร็จแล้วจะเรียกใช้ฟังก์ชันเริ่มต้นจริงซึ่งจะตั้งค่าทุกอย่างตอนนี้ข้อมูลทั้งหมดถูกดึงมา

หากลำดับของการดึงข้อมูลมีความสำคัญ - หรือหากเว็บเซิร์ฟเวอร์ไม่สามารถรับคำขอหลายรายการในเวลาเดียวกันคุณจะต้องมีสิ่งต่อไปนี้:

ใน onload () http get แรกจะเปิดตัว ในการเรียกกลับครั้งที่สองจะเปิดตัว ในการโทรกลับครั้งที่สามและอื่น ๆ โดยการโทรกลับแต่ละครั้งจะเรียกใช้ HTTP GET ถัดไป เมื่อคนสุดท้ายกลับมามันจะเรียกรูทีนจริง init ()


2

จะเกิดอะไรขึ้นถ้าคุณโทรแบบซิงโครนัสในรหัสการผลิต

ท้องฟ้าถล่มลงมา

ไม่จริงจังผู้ใช้ไม่ชอบเบราว์เซอร์ที่ถูกล็อก


2
คำถามคือ "ทำไมต้องใช้ XMLHTTPREQUEST" ไม่ "ทำไมต้องทำหรือไม่ซิงค์การโทร"
Itay Moav -Malimovka

1
หากคุณเพิ่มระยะหมดเวลาที่เหมาะสมซึ่งไม่น่าจะเป็นปัญหา
Greg

1
เขาขอใช้กรณีการโทรซิงค์ ... ไม่ใช่สำหรับข้อเสียของพวกเขา (ตอนนี้เราทุกคนรู้เรื่องนี้แล้ว ... )
Stijn de Witt

ผู้ใช้อะไร ผู้ใช้ทุกคนเหมือนกันหรือไม่ วิศวกรทำการทดสอบในพื้นที่อย่างไร? ... ดังนั้นการเข้าถึงไฟล์ของระบบไฟล์ที่มีความล่าช้าน้อยมาก ????
user2800679

2

ฉันใช้มันเพื่อตรวจสอบชื่อผู้ใช้ในระหว่างการตรวจสอบว่าไม่มีชื่อผู้ใช้อยู่แล้ว

ฉันรู้ว่ามันจะดีกว่าถ้าทำแบบอะซิงโครนัส แต่ฉันควรใช้รหัสอื่นสำหรับกฎการตรวจสอบนี้โดยเฉพาะ ผมอธิบายดีกว่า การตั้งค่าการตรวจสอบความถูกต้องของฉันใช้ฟังก์ชันการตรวจสอบความถูกต้องบางอย่างซึ่งส่งคืนจริงหรือเท็จขึ้นอยู่กับว่าข้อมูลนั้นถูกต้อง

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


เคล็ดลับอย่างหนึ่งในสถานการณ์ดังกล่าวคือให้ฟังก์ชันตรวจสอบความถูกต้องเพียงแค่ตรวจสอบแฟล็ก (ซึ่งเริ่มต้นด้วยfalse) และตั้งค่าเป็นจริงหรือเท็จเมื่อเซิร์ฟเวอร์ตอบสนอง ในการเปลี่ยนแปลงของฟิลด์คุณรีเซ็ตแฟล็กและเรียกเซิร์ฟเวอร์อีกครั้ง
Stijn de Witt

2

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

ปัญหาในแนวทางนี้คือคุณ "บล็อก" เบราว์เซอร์ของผู้ใช้จนกว่าการดำเนินการจะเสร็จสิ้น (จนกว่าคำขอจะส่งคืนเสร็จสิ้นโหลด ฯลฯ ) ดังนั้นควรระมัดระวังในการใช้งาน


คำถามคือ "ทำไมต้องใช้ XMLHTTPREQUEST" ไม่ใช่ "ทำไมต้องซิงค์การโทร"
Itay Moav -Malimovka

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

2

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

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


2

SYNC vs ASYNC: อะไรคือความแตกต่าง?

โดยทั่วไปแล้วจะเดือดลงถึงสิ่งนี้:

console.info('Hello, World!');
doSomething(function handleResult(result) {
    console.info('Got result!');
});
console.info('Goodbye cruel world!');

เมื่อdoSomethingใดที่ซิงโครนัสสิ่งนี้จะพิมพ์:

Hello, World!
Got result!
Goodbye cruel world!

ในทางตรงกันข้ามหากdoSomethingเป็นแบบอะซิงโครนัสสิ่งนี้จะพิมพ์:

Hello, World!
Goodbye cruel world!
Got result!

เนื่องจากฟังก์ชันdoSomethingกำลังทำงานแบบอะซิงโครนัสฟังก์ชันจึงส่งกลับก่อนที่จะทำงานเสร็จ ดังนั้นเราจะได้ผลลัพธ์หลังจากการพิมพ์เท่านั้นGoodbye cruel world!

หากเราขึ้นอยู่กับผลลัพธ์ของการโทรแบบไม่ซิงค์เราจำเป็นต้องวางรหัสที่ขึ้นอยู่กับการโทรกลับ:

console.info('Hello, World!');
doSomething(function handleResult(result) {
    console.info('Got result!');
    if (result === 'good') {
        console.info('I feel great!');
    }
    else {
        console.info('Goodbye cruel world!');
    }
});

ด้วยเหตุนี้ความจริงที่ว่า 2 หรือสามสิ่งต้องเกิดขึ้นตามลำดับจึงไม่มีเหตุผลที่จะทำพร้อมกัน (แม้ว่ารหัสการซิงค์จะง่ายกว่าสำหรับคนส่วนใหญ่ที่จะทำงานด้วย)

ทำไมต้องใช้ XMLHTTPREQUEST แบบซิงโครนัส

มีบางสถานการณ์ที่คุณต้องการผลลัพธ์ก่อนที่ฟังก์ชันที่เรียกจะเสร็จสมบูรณ์ พิจารณาสถานการณ์นี้:

function lives(name) {
    return (name !== 'Elvis');
}
console.info('Elvis ' + (lives('Elvis') ? 'lives!' : 'has left the building...');

สมมติว่าเราไม่สามารถควบคุมรหัสการโทร ( console.infoสาย) และจำเป็นต้องเปลี่ยนฟังก์ชั่นlivesเพื่อถามเซิร์ฟเวอร์ ... ไม่มีทางที่เราจะร้องขอ async ไปยังเซิร์ฟเวอร์จากภายในได้livesและยังคงได้รับคำตอบก่อนที่จะlivesเสร็จสมบูรณ์ ดังนั้นเราจะไม่ทราบว่าจะกลับหรือtrue falseวิธีเดียวที่จะได้ผลลัพธ์ก่อนที่ฟังก์ชันจะเสร็จสมบูรณ์คือการร้องขอแบบซิงโครนัส

ตามที่Sami Samhuriกล่าวไว้ในคำตอบของเขาสถานการณ์จริงที่คุณอาจต้องการคำตอบสำหรับคำขอเซิร์ฟเวอร์ของคุณก่อนที่ฟังก์ชันของคุณจะยุติคือonbeforeunloadเหตุการณ์เนื่องจากเป็นฟังก์ชันสุดท้ายจากแอปของคุณที่จะทำงานก่อนที่หน้าต่างจะถูกปิด

ฉันไม่จำเป็นต้องโทรซิงค์ แต่ฉันใช้พวกเขาทุกที่ที่พวกเขาง่ายกว่า

กรุณาอย่า การโทรแบบซิงโครนัสจะล็อกเบราว์เซอร์ของคุณและทำให้แอปไม่ตอบสนอง แต่คุณพูดถูก รหัส Async ยากกว่า อย่างไรก็ตามมีวิธีที่จะทำให้จัดการกับมันได้ง่ายขึ้นมาก ไม่ง่ายเหมือนการซิงค์รหัส แต่มันกำลังใกล้เข้ามา: Promise s

นี่คือตัวอย่าง: การเรียกแบบ asynch สองครั้งควรดำเนินการให้สำเร็จก่อนที่โค้ดส่วนที่สามจะทำงาน:

var carRented = rentCar().then(function(car){
  gasStation.refuel(car);
});

var hotelBooked = bookHotel().then(function(reservation) {
  reservation.confirm();
});

Promise.all([carRented, hotelBooked]).then(function(){
  // At this point our car is rented and our hotel booked.
  goOnHoliday();
});

นี่คือวิธีที่คุณจะนำไปใช้bookHotel:

function bookHotel() {
  return new Promise(function(resolve, reject){
    if (roomsAvailable()) {
      var reservation = reserveRoom();
      resolve(reservation);
    }
    else {
      reject(new Error('Could not book a reservation. No rooms available.'));
    }
  });
}

ดูเพิ่มเติม: เขียนดีกว่า JavaScript กับสัญญา


1
"โปรดอย่าการโทรแบบซิงโครนัสจะล็อกเบราว์เซอร์ของคุณและทำให้แอปไม่ตอบสนอง" นี่ไม่ใช่ปัญหาเสมอไป ลองนึกภาพคุณกำลังทดสอบ localhost และคุณเป็นนักพัฒนาซอฟต์แวร์
user2800679

2

XMLHttpRequestโดยปกติจะใช้สำหรับคำขอแบบอะซิงโครนัส บางครั้ง (สำหรับการดีบักหรือตรรกะทางธุรกิจที่เฉพาะเจาะจง) คุณต้องการเปลี่ยนการเรียก async ทั้งหมด / หลายรายการในหน้าเดียวเพื่อซิงค์

คุณต้องการที่จะทำโดยไม่ต้องเปลี่ยนทุกอย่างในรหัส JS ของคุณ แฟล็ก async / sync ทำให้คุณมีความสามารถดังกล่าวและหากได้รับการออกแบบอย่างถูกต้องคุณต้องเปลี่ยนเพียงบรรทัดเดียวในรหัสของคุณ / เปลี่ยนค่าหนึ่งvarในระหว่างเวลาดำเนินการ


1

Firefox (และเป็นไปได้ว่าเบราว์เซอร์ที่ไม่ใช่ IE ทั้งหมด) ไม่รองรับ async XHR timeOut

  1. การอภิปราย Stackoverflow
  2. Mozilla Firefox XMLHttpRequest

HTML5 WebWorkersรองรับการหมดเวลา ดังนั้นคุณอาจต้องการตัดการร้องขอ XHR การซิงค์ไปยัง WebWorker ด้วยการหมดเวลาเพื่อใช้งาน XHR แบบ async ที่มีลักษณะการหมดเวลา


1

ฉันเพิ่งมีสถานการณ์ที่คำขอแบบอะซิงโครนัสสำหรับรายการ URL ที่เรียกต่อเนื่องกันโดยใช้ forEach (และ a for loop) จะทำให้คำขอที่เหลือถูกยกเลิก ฉันเปลี่ยนเป็นซิงโครนัสและทำงานได้ตามที่ตั้งใจไว้


1

การใช้คำขอ HTTP แบบซิงโครนัสเป็นแนวทางปฏิบัติทั่วไปในธุรกิจโฆษณาบนอุปกรณ์เคลื่อนที่

บริษัท (หรือที่เรียกว่า "ผู้เผยแพร่โฆษณา") ที่สร้างแอปพลิเคชันมักเรียกใช้โฆษณาเพื่อสร้างรายได้ ด้วยเหตุนี้พวกเขาจึงติดตั้ง SDK โฆษณาลงในแอปของตน มีอยู่มากมาย (MoPub, Ogury, TapJob, AppNext, Google Ads AdMob)

SDK เหล่านี้จะแสดงโฆษณาในมุมมองเว็บ

เมื่อแสดงโฆษณาแก่ผู้ใช้จะต้องมีประสบการณ์ที่ราบรื่นโดยเฉพาะอย่างยิ่งเมื่อเล่นวิดีโอ ไม่ควรมีการบัฟเฟอร์หรือโหลดในขณะใด ๆ

เพื่อแก้ปัญหานี้precachingใช้ ที่โหลดสื่อ (รูปภาพ / วิดีโอ / ฯลฯ ) พร้อมกันในพื้นหลังของมุมมองเว็บ

ทำไมไม่ทำแบบอะซิงโครนัส

  1. นี่เป็นส่วนหนึ่งของมาตรฐานที่ยอมรับกันทั่วโลก
  2. SDK จะรับฟังonloadเหตุการณ์เพื่อให้ทราบว่าโฆษณา "พร้อม" ที่จะแสดงต่อผู้ใช้เมื่อใด

ด้วยการเลิกใช้งานXMLHttpRequests แบบซิงโครนัสธุรกิจโฆษณามักจะถูกบังคับให้เปลี่ยนมาตรฐานในอนาคตเว้นแต่จะสามารถกำหนดวิธีอื่นได้


0

XHR แบบซิงโครนัสมีประโยชน์มากสำหรับการพัฒนาเครื่องมือและ / หรือกรอบงานภายใน (ที่ไม่ใช่การผลิต) ตัวอย่างเช่นคุณต้องการโหลดไลบรารีโค้ดพร้อมกันในการเข้าถึงครั้งแรกเช่นนี้:

get draw() 
{
    if (!_draw)
    {
       let file;
       switch(config.option)
       {
           case 'svg':
              file = 'svgdraw.js';
              break;
           case 'canvas':
              file = 'canvasdraw.js';
              break;
           default:
              file = 'webgldraw.js';
       }

       var request = new XMLHttpRequest();
       request.open('GET', file, false);
       request.send(null);
       _draw = eval(request.responseText);
    }

    return _draw;
}

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

ดังนั้นรหัสของคุณอาจมีลักษณะดังนี้:

foo.drawLib.draw.something(); //loaded on demand

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

ขีด จำกัด ของสิ่งที่คุณสามารถทำได้กับสิ่งนี้สำหรับเครื่องมือและเฟรมเวิร์ก (ทำงานในพื้นที่) นั้นถูก จำกัด ด้วยจินตนาการของคุณเท่านั้น แม้ว่าจินตนาการจะมีข้อ จำกัด เล็กน้อยในโลกของ JavaScript


-1

นี่เป็นเหตุผลที่ดีประการหนึ่ง ฉันต้องการทำคำขอ http จากนั้นเรียกคลิก () บนประเภทอินพุต = ไฟล์ขึ้นอยู่กับผลลัพธ์ สิ่งนี้ไม่สามารถทำได้ด้วย xhr แบบอะซิงโครนัสหรือการดึงข้อมูล การเรียกกลับสูญเสียบริบท "การดำเนินการของผู้ใช้" ดังนั้นการคลิกโทร () จึงถูกละเว้น xhr ซิงโครนัสบันทึกเบคอนของฉัน

onclick(event){
    //here I can, but I don't want to.
    //document.getElementById("myFileInput").click();
    fetch("Validate.aspx", { method : "POST", body: formData, credentials: "include" })
    .then((response)=>response.json())
    .then(function (validResult) {
        if (validResult.success) {
            //here, I can't.
            document.getElementById("myFileInput").click();
        }
    });
}

บันทึกไว้ใน var
Es Noguera
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.