ทำความเข้าใจกับคำสัญญาใน Node.js


147

จากสิ่งที่ฉันเข้าใจมีสามวิธีในการเรียกใช้โค้ดอะซิงโครนัส:

  1. กิจกรรมเช่น request.on("event", callback);
  2. การโทรกลับเช่น fs.open(path, flags, mode, callback);
  3. สัญญา

ฉันพบไลบรารี่สัญญาโหนดแต่ไม่เข้าใจ

ใครช่วยอธิบายเกี่ยวกับสัญญาได้บ้างและทำไมฉันถึงควรใช้มัน

ทำไมมันถูกลบออกจาก Node.js


บทความนี้อธิบายได้ค่อนข้างดี เมื่อพูดถึงการติดตั้งที่ใช้งานได้ใน node.js ลองดูFutures
Sean Kinsey

นี่เป็นซีรี่ส์ที่ยอดเยี่ยมที่ฉันเคยสร้างคลาสสัญญาของฉัน: Let's Make a Framework: Promisesวิดีโอที่เกี่ยวกับ jQuery Deferred: blog.bigbinary.com/2011/09/03/jquery-deferred.html
Tom Winter

คำตอบ:


91

สัญญาใน node.js สัญญาว่าจะทำงานบางอย่างและมีการเรียกกลับแยกต่างหากที่จะดำเนินการเพื่อความสำเร็จและความล้มเหลวเช่นเดียวกับการจัดการหมดเวลา อีกวิธีในการคิดถึงสัญญาใน node.js ก็คือพวกมันเป็นตัวส่งสัญญาณที่สามารถปล่อยเหตุการณ์ได้เพียงสองเหตุการณ์เท่านั้น: ความสำเร็จและข้อผิดพลาด

สิ่งที่ยอดเยี่ยมเกี่ยวกับสัญญาคือคุณสามารถรวมมันเข้ากับเชนพึ่งพา (ทำสัญญา C เฉพาะเมื่อสัญญา A และสัญญา B เสร็จสมบูรณ์)

โดยการลบออกจาก core node.js มันสร้างความเป็นไปได้ของการสร้างโมดูลที่มีการใช้งานที่แตกต่างกันของสัญญาที่สามารถนั่งอยู่ด้านบนของแกน บางส่วนของเหล่านี้เป็นโหนดสัญญาและฟิวเจอร์ส


10
@weng ไม่มันไม่ใช่
Ivo Wetzel

98

เนื่องจากคำถามนี้ยังคงมีหลายมุมมอง (เช่นของฉัน) ฉันต้องการชี้ให้เห็นว่า:

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

9
ลองดูที่github.com/medikoo/deferredนี่Q เป็นหนึ่งในคนแรกและเป็นแรงบันดาลใจให้กับการใช้งานหลายอย่างที่ปรากฎในภายหลัง แต่น่าเสียดายที่มันช้ามากและ "ทฤษฎี" ในบางส่วนมันเล่นได้ไม่ดีนัก สถานการณ์ในโลกแห่งความเป็นจริง
Mariusz Nowak

ฉันจะตรวจสอบวิดีโอนี้เกี่ยวกับสัญญาโดยหนึ่งในผู้สร้างของ RSVP.js youtube.com/…
runspired

23
การอัปเดต 2014 - Bluebirdนั้นเร็วที่สุดและเป็นหนึ่งเดียวที่มีความสามารถในการดีบั๊กที่ดีที่สุดในปัจจุบัน
Benjamin Gruenbaum

19

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

 var request = new Promise(function(resolve, reject) {
   //do an ajax call here. or a database request or whatever.
   //depending on its results, either call resolve(value) or reject(error)
   //where value is the thing which the operation's successful execution returns and
   //error is the thing which the operation's failure returns.
 });

 request.then(function successHandler(result) {
   //do something with the result
 }, function failureHandler(error) {
  //handle
 });

ข้อมูลจำเพาะของสัญญาระบุว่าสัญญานั้นเป็นของ

then

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

var doStuff = firstAsyncFunction(url) {
                return new Promise(function(resolve, reject) {
                       $.ajax({
                        url: url,
                        success: function(data) {
                            resolve(data);
                        },
                        error: function(err) {
                             reject(err); 
                        } 
                  });
               };
doStuff
  .then(secondAsyncFunction) //returns a promise
  .then(thirdAsyncFunction); //returns a promise

หากต้องการทราบข้อมูลเพิ่มเติมเกี่ยวกับสัญญาและเหตุผลที่ทำไมพวกเขาถึงเจ๋งสุด ๆ ให้เช็คเอาต์บล็อกของ Domenic: http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/


12

นี้กวดวิชาใหม่ในสัญญาจากผู้เขียนของPouchDBน่าจะดีที่สุดที่ผมเคยเห็นที่ใดก็ได้ มันครอบคลุมความผิดพลาดมือใหม่อย่างคลาสสิกอย่างฉลาดแสดงให้คุณเห็นรูปแบบการใช้งานที่ถูกต้องและแม้กระทั่งรูปแบบการต่อต้านบางอย่างที่ยังคงใช้กันโดยทั่วไป - แม้ในบทเรียนอื่น ๆ !!

สนุก!

ป.ล. ฉันไม่ได้ตอบบางส่วนของคำถามนี้เนื่องจากคนอื่น ๆ ได้รับการคุ้มครองอย่างดี


คำขอโทษเพียงอย่างเดียวของฉันคือการบังคับให้คุณอ่านเรื่องตลกในตอนท้ายของความผิดพลาดขั้นสูง # 4
Tony O'Hagan

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

ความผิดพลาดขั้นสูง # 4สามารถแก้ไขได้โดยใช้วิธีการที่แตกต่างกันจำนวนมากดูฉันจะเข้าถึงผลลัพธ์ที่ได้สัญญาไว้ในห่วงโซ่. แล้ว () ( รูปแบบการปิดที่พวกเขาแนะนำไม่น่าจะเป็นที่นิยมมาก)
Bergi

ฉันคิดว่าคำตอบสำหรับลิงค์นี้ควรเป็นความเห็นที่ดีกว่า โปรดระบุประเด็นหลักของบทความนั้นในคำตอบของคุณที่นี่
Bergi

7

Mike Taulty มีวิดีโอหลายชุดซึ่งแต่ละวิดีโอมีความยาวน้อยกว่าสิบนาทีซึ่งอธิบายวิธีการทำงานของห้องสมุดสัญญา WinJS

วิดีโอเหล่านี้มีข้อมูลค่อนข้างมากและไมค์ก็จัดการแสดงพลังของ Promise API ด้วยตัวอย่างโค้ดที่ได้รับการคัดสรรมาอย่างดี

var twitterUrl = "http://search.twitter.com/search.json?q=windows";
var promise = WinJS.xhr({ url: twitterUrl });

 promise = promise.then(
     function (xhr) {
     },
     function (xhr) {
         // handle error
     });

การรักษาวิธีจัดการข้อยกเว้นนั้นดีเป็นพิเศษ

ทั้งๆที่มีการอ้างอิง WinJs นี้เป็นชุดวิดีโอความสนใจทั่วไปเพราะ API สัญญามีความคล้ายคลึงกันในวงกว้างในการใช้งานหลายอย่าง

RSVPเป็นการนำ Promise ที่มีน้ำหนักเบาซึ่งผ่านชุดทดสอบ Promise / A + ฉันค่อนข้างชอบ API เพราะมันคล้ายกับอินเตอร์เฟส WinJS

อัพเดท เม.ย. 2557

อนึ่งขณะนี้ไลบรารี WinJS เป็นโอเพ่นซอร์สแล้ว


1
+1 นี่เป็นตัวอย่างแรกที่ฉันเห็นว่าเหมาะสมกับฉันและใช้งานง่าย ยังไงก็ตามสมองของฉันไม่สามารถแยกวิเคราะห์ทั้งหมดdeferredsและresolveและdeferred.promise.thenและกำหนดไว้ล่วงหน้าpromiseActionsในเอกสารประกอบ Q Library ที่เป็นที่นิยม โอกาสใดที่คุณรู้ว่าสิ่งนี้ตรงไปตรงมาสำหรับNode.js ?
Redsandro

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

ตัวอย่างที่ดี นอกจากนี้ฉันได้แก้ไขลิงก์แรกของคุณที่ตายแล้ว
stonedauwg

5

ข้อดีอีกประการของสัญญาคือการจัดการข้อผิดพลาดและข้อยกเว้นการขว้างปาและจับได้ดีกว่าการพยายามจัดการกับการเรียกกลับ

ครามดำเนินการสัญญาห้องสมุดและช่วยให้คุณร่องรอยสแต็คยาวดีเป็นอย่างมากอย่างรวดเร็วและเตือนเกี่ยวกับข้อผิดพลาดไม่ถูกตรวจจับ นอกจากนี้ยังเร็วกว่าและใช้หน่วยความจำน้อยกว่าไลบรารีสัญญาอื่น ๆ ตามhttp://bluebirdjs.com/docs/benchmarks.html


4

สัญญาคืออะไร?

คำมั่นสัญญาเป็นเพียงวัตถุที่แสดงผลลัพธ์ของการดำเนินการแบบอะซิงก์ สัญญาสามารถอยู่ในสถานะใด ๆ ต่อไปนี้ 3 สถานะ:

รอดำเนินการ :: นี่คือสถานะเริ่มต้นหมายถึงสัญญาไม่สมบูรณ์หรือปฏิเสธ

เติมเต็ม :: นี่หมายความว่าสัญญาได้รับการเติมเต็มแล้วหมายถึงมูลค่าที่แสดงโดยสัญญาพร้อมใช้งานแล้ว

ปฏิเสธ :: หมายความว่าการดำเนินการล้มเหลวและไม่สามารถทำตามสัญญาได้ นอกเหนือจากรัฐมีสามหน่วยงานที่สำคัญที่เกี่ยวข้องกับสัญญาที่เราต้องเข้าใจ

  1. executor function :: ฟังก์ชั่น executor กำหนดการดำเนินการ async ซึ่งจะต้องมีการดำเนินการและมีผลเป็นตัวแทนของสัญญา มันเริ่มดำเนินการทันทีที่วัตถุสัญญาถูกเตรียมใช้งาน

  2. แก้ไข :: แก้ไขเป็นพารามิเตอร์ที่ส่งผ่านไปยังฟังก์ชั่นของผู้บริหารและในกรณีที่ผู้บริหารทำงานได้สำเร็จแล้วการแก้ไขนี้เรียกว่าการส่งผ่านผลลัพธ์

  3. ปฏิเสธ :: ปฏิเสธเป็นพารามิเตอร์อื่นที่ส่งผ่านไปยังฟังก์ชั่นผู้บริหารและมันจะใช้เมื่อฟังก์ชั่นผู้บริหารล้มเหลว เหตุผลความล้มเหลวสามารถส่งผ่านไปยังการปฏิเสธ

ดังนั้นเมื่อใดก็ตามที่เราสร้างวัตถุสัญญาเราจะให้ผู้บริหารแก้ไขและปฏิเสธ

อ้างอิง :: สัญญา


0

ฉันเคยดูสัญญาใน node.js เมื่อเร็ว ๆ นี้ ถึงวันที่when.jsดูเหมือนจะเป็นหนทางไปเนื่องจากความเร็วและการใช้ทรัพยากร แต่เอกสารในq.jsทำให้ฉันเข้าใจมากขึ้น ดังนั้นใช้ when.js แต่เป็น q.js docs เพื่อทำความเข้าใจกับหัวเรื่อง

จากreadme ของq.jsบน github:

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


0

วัตถุสัญญาแสดงถึงความสมบูรณ์หรือความล้มเหลวของการดำเนินการแบบอะซิงโครนัส

ดังนั้นในการทำสัญญาคุณต้องมีสองส่วน: -

1. การสร้างสัญญา:

คอนสตรัคสัญญารับฟังก์ชั่นที่เรียกว่าตัวดำเนินการที่มี 2 พารามิเตอร์การแก้ไขและปฏิเสธ

function example(){
   return new Promise (function(resolve , reject){   //return promise object
      if(success){
         resolve('success');  //onFullfiled
      }else{
         reject('error');     //onRejected
      }
   })
}

2. การจัดการสัญญา:

วัตถุสัญญามี 3 วิธีในการจัดการวัตถุสัญญา: -

1.Promise.prototype.catch (onRejected)

2.Promise.prototype.then (onFullfiled)

3.Promise.prototype.finally (onFullfiled, onRejected)

example.then((data) =>{
  //handles resolved data
  console.log(data); //prints success     
}).catch((err) => {
  //handles rejected error 
  console.log(err);  //prints error
})
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.