HttpPromise เชิงมุม: ความแตกต่างระหว่างเมธอด `success` /` error` และการโต้เถียงของ `then`


177

ตามAngularJS doc การเรียกเพื่อ$httpส่งคืนสิ่งต่อไปนี้:

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

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

  • การเรียกกลับสำเร็จ / ข้อผิดพลาดถูกส่งผ่านเป็นอาร์กิวเมนต์ของ promise.then
  • การเรียกกลับถูกส่งผ่านเป็นอาร์กิวเมนต์สำหรับpromise.success/ promise.errorวิธีของสัญญา

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

คำตอบ:


156

NBคำตอบนี้ไม่ถูกต้องตามความเป็นจริง; ตามที่ระบุไว้โดยความคิดเห็นด้านล่างความสำเร็จ () จะคืนสัญญาเดิม ฉันจะไม่เปลี่ยน และปล่อยไว้ที่ OP เพื่อแก้ไข


ข้อแตกต่างที่สำคัญระหว่าง 2 คือการ.then()โทรจะส่งคืนสัญญา (แก้ไขด้วยค่าที่ส่งคืนจากการโทรกลับ) ในขณะที่.success()เป็นวิธีการลงทะเบียนการโทรกลับแบบดั้งเดิมมากกว่าเดิมและจะไม่ส่งคืนสัญญา

เรียกกลับตามสัญญา ( .then()) ทำให้ง่ายต่อสัญญาโซ่ (ทำสายแปลผลและจากนั้นทำสายอื่นตีความผลการทำสายอื่น ๆ ฯลฯ )

.success()วิธีการเป็นคล่องตัววิธีการความสะดวกสบายเมื่อคุณไม่จำเป็นต้องโทรห่วงโซ่มิได้ทำงานร่วมกับสัญญา API (ตัวอย่างเช่นในการกำหนดเส้นทาง)

ในระยะสั้น:

  • .then() - พลังเต็มรูปแบบของ API การให้สัญญา แต่มีความละเอียดมากกว่าเล็กน้อย
  • .success() - ไม่ส่งคืนสัญญา แต่เสนอไวยากรณ์ที่สะดวกกว่าเล็กน้อย

44
อีกความแตกต่างที่ยิ่งใหญ่คือการที่thenเรียกกลับใช้อาร์กิวเมนต์เดียว - การตอบสนอง - ในขณะที่successและerrorใช้เวลาแต่ละองค์ประกอบของการตอบสนองเป็น arguments-- data, status, และheader config
Michelle Tilley

1
@BrandonTilley ถูกต้องทั้งหมด แต่ผู้เขียนคำถามคิดออกมาแล้วดังนั้นฉันไม่รู้สึกว่าฉันจำเป็นต้องทำซ้ำที่นี่
pkozlowski.opensource

45
แม้ว่าเอกสารจะไม่พูดอย่างชัดเจน แต่เราสามารถอนุมานได้ว่า.success()วิธีการส่งคืนวัตถุสัญญา $ http ต้นฉบับเนื่องจากห่วงโซ่$http(...).success(...).error(...)เป็นไปได้ หากเป็นไปได้ด้วยเหตุผลที่ตรงกันข้าม$http(...).error(...).success(...)ก็เป็นไปได้แล้วก็.error()ควรกลับวัตถุสัญญาเดิม ความแตกต่างที่โดดเด่นของ .then()มันคือมันคืนสัญญาใหม่
บีทรูทบีทรูท

2
ซอร์สโค้ดจาก angular.js ของบริการ $ http: promise.success = function(fn) { promise.then(function(response) { fn(response.data, response.status, response.headers, config); }); return promise; };
Alex Che

6
โปรดทราบว่าsuccessเลิกใช้แล้ว จากdocs.angularjs.org/api/ng/service/$http#deprecation-notice The $http legacy promise methods success and error have been deprecated. Use the standard then method instead. If $httpProvider.useLegacyPromiseExtensions is set to false then these methods will throw $http/legacy error.
Sam Barnum

204

มีคำตอบที่ดีอยู่ที่นี่แล้ว แต่มันก็คุ้มค่าที่จะขับรถกลับบ้านด้วยข้อแตกต่างของความเท่าเทียม

  • success() ส่งคืนสัญญาเดิม
  • then() ส่งคืนสัญญาใหม่

ความแตกต่างคือการthen()ขับเคลื่อนตามลำดับเนื่องจากการโทรแต่ละครั้งส่งคืนสัญญาใหม่

$http.get(/*...*/).
  then(function seqFunc1(response){/*...*/}).
  then(function seqFunc2(response){/*...*/})
  1. $http.get()
  2. seqFunc1()
  3. seqFunc2()

success() ไดรฟ์การดำเนินงานแบบขนานเนื่องจากจัดการถูกผูกมัดกับสัญญาเดียวกัน

$http(/*...*/).
  success(function parFunc1(data){/*...*/}).
  success(function parFunc2(data){/*...*/})
  1. $http.get()
  2. parFunc1(), parFunc2()ในแบบคู่ขนาน

3
หมายเหตุการตอบสนองสัญญาใหม่ที่ส่งคืนเมื่อthenถึงผลลัพธ์successและerrorวิธีการจะหายไป นอกจากนี้สำหรับการตอบสนองข้อผิดพลาด http (เช่น 404) ครั้งแรกthenในhttp.then(ok, err).then(ok, err)จะผ่านไปerrจัดการ แต่คนต่อไปนี้จะผ่านเข้าไปในokตัวจัดการ โดยทั่วไปhttp.success().error().success().error()มีความสามารถในการเชื่อมโยงได้ แต่สัญญา $ q นั้นแตกต่างกันมากเนื่องจากเป็นสัญญาและลำดับการจัดการโดยเฉพาะ (ไม่ใช่การจัดการคำขอ http) ฉันมีความยากลำบากในการทำความเข้าใจสิ่งนี้จนกว่าฉันจะมองอย่างใกล้ชิด
jimmont

1
@ jimmont successและerrorไม่ใช่ API ปกติของสัญญาพวกเขาจะยึดติดกับค่าส่งคืนของ $ http ()
event_jr

ขอบคุณ @event_jr นี่ชัดเจนสำหรับฉันและเรียกออกมาในเอกสาร สิ่งที่ไม่ชัดเจน (สำหรับฉัน) คือ $ q และ $ http แก้ปัญหาที่แตกต่างกันอย่างไรรวมถึงการคืนสัญญาใหม่เทียบกับการส่งผ่านสัญญาเดียวกัน - ตามที่ระบุไว้ในคำตอบ (มีประโยชน์มาก) ของคุณ
jimmont

1
คุณหมายถึงอะไรขนานกันเนื่องจาก JS เป็นเธรดเดียว? คุณหมายถึงคำสั่งการดำเนินการที่ไม่ได้กำหนดไว้หรือไม่
Derek

2
@Derek ที่สองsuccessจะดำเนินการหลังจากคนแรกที่ได้ดำเนินการ แต่ก่อนที่สัญญาใด ๆ กลับมาจากการแก้ไขในขณะที่สองthenจะรอ หากคุณไม่ได้กลับมาทำสัญญาแล้วทั้งคู่ก็ทำแบบเดียวกัน
Tamlyn

114

ตัวอย่างโค้ดสำหรับการร้องขอ GET แบบง่าย บางทีนี่อาจช่วยทำความเข้าใจความแตกต่าง การใช้then:

$http.get('/someURL').then(function(response) {
    var data = response.data,
        status = response.status,
        header = response.header,
        config = response.config;
    // success handler
}, function(response) {
    var data = response.data,
        status = response.status,
        header = response.header,
        config = response.config;
    // error handler
});

ใช้success/ error:

$http.get('/someURL').success(function(data, status, header, config) {
    // success handler
}).error(function(data, status, header, config) {
    // error handler
});

5
ขอบคุณ แต่คำถามนั้นเกี่ยวกับความแตกต่างในสิ่งที่ฟังก์ชั่นเหล่านี้ทำหรือเหตุผลที่ทำให้ทั้งคู่มีอยู่ถ้าพวกเขาทำสิ่งเดียวกัน ความแตกต่างในวิธีการใช้งานนั้นสามารถเข้าใจได้จากเอกสาร
ejoubaud

39
ฉันชอบตัวอย่างรหัสสั้น ๆ และฉันโพสต์ไว้ที่นี่ เอกสารเชิงมุมบางครั้งพลาดตัวอย่างที่แม่นยำสั้น ๆ
TheHippo

2
มันเป็นสิ่งสำคัญที่เน้นถึงข้อเท็จจริงที่ว่าวัตถุตอบสนองของกระทู้แรกนั้นมี "ข้อมูลสถานะการหายตัวและการกำหนดค่า" ของกระทู้ที่สอง นั่นหมายความว่าวัตถุตอบสนองมีระดับความลึกหนึ่งระดับ
geoom

มีประโยชน์ใด ๆ ในการส่งค่าการตอบกลับไปยังตัวแปรที่data,status,header,configมากกว่าแค่ส่งคืนresponseหรือไม่?
ᴍᴀᴛᴛʙᴀᴋᴇʀ

27

.then () นั้นสามารถเชื่อมโยงได้และจะรอก่อนหน้านี้จากนั้น () เพื่อแก้ไข

.success () และ .error () สามารถถูกล่ามโซ่ได้ แต่พวกเขาจะยิงพร้อมกันทั้งหมด (ดังนั้นจึงไม่ค่อยชี้ไปที่)

.success () และ .error () เหมาะสำหรับการโทรแบบง่าย (ผู้สร้างง่าย):

$http.post('/getUser').success(function(user){ 
   ... 
})

ดังนั้นคุณไม่ต้องพิมพ์สิ่งนี้:

$http.post('getUser').then(function(response){
  var user = response.data;
})

แต่โดยทั่วไปแล้วฉันจัดการข้อผิดพลาดทั้งหมดด้วย. catch ():

$http.get(...)
    .then(function(response){ 
      // successHandler
      // do some stuff
      return $http.get('/somethingelse') // get more data
    })
    .then(anotherSuccessHandler)
    .catch(errorHandler)

ถ้าคุณต้องการสนับสนุน <= IE8 ให้เขียน. catch () และ. สุดท้าย () ดังนี้ (วิธีสงวนไว้ใน IE):

    .then(successHandler)
    ['catch'](errorHandler)

ตัวอย่างการทำงาน:

นี่คือสิ่งที่ฉันเขียนในรูปแบบ codey เพิ่มเติมเพื่อรีเฟรชหน่วยความจำของฉันว่ามันเล่นกับการจัดการข้อผิดพลาด ฯลฯ :

http://jsfiddle.net/nalberg/v95tekz2/


คำตอบเดียวที่แสดงว่า "คืนสัญญาอีกครั้ง" ทำงานอย่างไร
zjk

17

เมื่อเสร็จแล้วนี่คือตัวอย่างรหัสที่แสดงถึงความแตกต่าง

success \ error:

$http.get('/someURL')
.success(function(data, status, header, config) {
    // success handler
})
.error(function(data, status, header, config) {
    // error handler
});

แล้ว:

$http.get('/someURL')
.then(function(response) {
    // success handler
}, function(response) {
    // error handler
})
.then(function(response) {
    // success handler
}, function(response) {
    // error handler
})
.then(function(response) {
    // success handler
}, function(response) {
    // error handler
}).

เยี่ยมมากคุณมีตัวอย่างที่การต่อข้อมูลจะมีประโยชน์หรือไม่
geoom

4
แนวคิดก็คือวิธีการ "ตามปกติ" นั้นมีประโยชน์มากกว่าเนื่องจากคุณสามารถเขียนการดำเนินการแบบอะซิงโครนัสได้ง่ายกว่ากัน
MichaelLo

2

ประกาศอย่างเป็นทางการ: ความสำเร็จและข้อผิดพลาดได้รับการคัดค้านโปรดใช้วิธีการมาตรฐานแล้วแทน

ประกาศการเลิกใช้: ความสำเร็จและข้อผิดพลาดของวิธีการทำสัญญา $ http ได้ถูกเลิกใช้แล้ว ใช้วิธีการมาตรฐานแทน ถ้า $ httpProvider.useLegacyPromiseExtensions ถูกตั้งค่าเป็นเท็จดังนั้นวิธีการเหล่านี้จะทำให้เกิดข้อผิดพลาด $ http / legacy

ลิงก์: https://code.angularjs.org/1.5.7/docs/api/ng/service/$http

สกรีนช็อต: ดูภาพหน้าจอ

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