jQuery รอการตัดบัญชีและสัญญา - .then () vs .done ()


473

ฉันอ่านเกี่ยวกับ jQuery รอการตัดบัญชีและสัญญาและฉันไม่เห็นความแตกต่างระหว่างการใช้.then()& .done()สำหรับการโทรกลับที่ประสบความสำเร็จ ฉันรู้ว่าEric Hyndsพูดถึงเรื่องนั้น.done()และ.success()แมปไปยังฟังก์ชั่นเดียวกัน แต่ฉันเดา.then()ว่าจะเป็นเช่นนั้นเพราะการเรียกกลับทั้งหมดถูกเรียกใช้เมื่อการดำเนินการที่ประสบความสำเร็จเสร็จสิ้น

ใครช่วยสอนฉันให้ฉันเกี่ยวกับการใช้ที่ถูกต้องได้ไหม


15
โปรดทราบว่าทุกคนที่ JQuery 3.0 เปิดตัวในเดือนมิถุนายน 2559 เป็นรุ่นแรกที่ตรงตามข้อกำหนดของสัญญา / A + และ ES2015 สัญญา การดำเนินการก่อนหน้านั้นมีความไม่ลงรอยกันกับสิ่งที่สัญญาควรจะส่งมอบ
Flimm

ฉันอัพเดตคำตอบของฉันพร้อมคำแนะนำที่ปรับปรุงแล้วสำหรับสิ่งที่จะใช้เมื่อใด
Robert Siemer

คำตอบ:


577

การโทรกลับที่แนบมากับdone()จะถูกไล่ออกเมื่อมีการแก้ไขรอการตัดบัญชี การเรียกกลับที่แนบมากับfail()จะถูกไล่ออกเมื่อถูกเลื่อนออกไปถูกปฏิเสธ

ก่อนหน้า jQuery 1.8 then()เป็นเพียงน้ำตาลประโยค:

promise.then( doneCallback, failCallback )
// was equivalent to
promise.done( doneCallback ).fail( failCallback )

ในฐานะของ 1.8 then()เป็นนามแฝงสำหรับpipe()และผลตอบแทนสัญญาใหม่ให้ดูที่นี่pipe()สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ

success()และerror()จะใช้ได้เฉพาะบนวัตถุที่ส่งกลับโดยการเรียกไปยังjqXHR ajax()พวกเขาเป็นนามแฝงง่ายdone()และfail()ตามลำดับ:

jqXHR.done === jqXHR.success
jqXHR.fail === jqXHR.error

นอกจากนี้done()ไม่ จำกัด เพียงการโทรกลับครั้งเดียวและจะกรองฟังก์ชันที่ไม่ใช่ฟังก์ชั่น (แม้ว่าจะมีข้อผิดพลาดกับสตริงในรุ่น 1.8 ที่ควรได้รับการแก้ไขใน 1.8.1):

// this will add fn1 to 7 to the deferred's internal callback list
// (true, 56 and "omg" will be ignored)
promise.done( fn1, fn2, true, [ fn3, [ fn4, 56, fn5 ], "omg", fn6 ], fn7 );

fail()เดียวกันจะไปสำหรับ


8
thenการคืนสัญญาใหม่เป็นสิ่งสำคัญที่ฉันขาดหายไป ฉันไม่เข้าใจว่าทำไมห่วงโซ่เช่น$.get(....).done(function(data1) { return $.get(...) }).done(function(data2) { ... })นั้นถึงล้มเหลวโดยdata2ไม่ได้กำหนด เมื่อฉันเปลี่ยนdoneไปthenใช้งานได้เพราะฉันต้องการท่อสัญญากันมากกว่าที่จะแนบตัวจัดการเพิ่มเติมกับสัญญาเดิม
wrschneider

5
jQuery 3.0 เป็นรุ่นแรกที่สอดคล้องกับข้อกำหนดของสัญญา / A + และ ES2015
Flimm

4
ฉันยังไม่เข้าใจว่าทำไมฉันจึงใช้อีกอันหนึ่ง หากฉันทำการโทร ajax และฉันต้องรอจนกว่าการโทรนั้นจะเสร็จสมบูรณ์ (หมายถึง reponse ถูกส่งคืนจากเซิร์ฟเวอร์) ก่อนที่ฉันจะโทร ajax อีกครั้งฉันจะใช้doneหรือthenไม่? ทำไม?
CodingYoshi

@CodeYoshi ลองอ่านคำตอบของฉันเพื่อตอบคำถามนั้นในที่สุด (ใช้งาน.then())
Robert Siemer

413

นอกจากนี้ยังมีความแตกต่างในวิธีการประมวลผลผลลัพธ์ที่ส่งคืน (เรียกว่าการโยง, doneไม่โยงในขณะที่thenสร้างสายเรียก)

promise.then(function (x) { // Suppose promise returns "abc"
    console.log(x);
    return 123;
}).then(function (x){
    console.log(x);
}).then(function (x){
    console.log(x)
})

ผลลัพธ์ต่อไปนี้จะถูกบันทึกไว้:

abc
123
undefined

ในขณะที่

promise.done(function (x) { // Suppose promise returns "abc"
    console.log(x);
    return 123;
}).done(function (x){
    console.log(x);
}).done(function (x){
    console.log(x)
})

จะได้รับสิ่งต่อไปนี้:

abc
abc
abc

---------- อัปเดต:

Btw ฉันลืมที่จะพูดถึงถ้าคุณส่งคืนสัญญาแทนค่าประเภทอะตอมสัญญาภายนอกจะรอจนกว่าสัญญาภายในจะแก้ไขได้:

promise.then(function (x) { // Suppose promise returns "abc"
    console.log(x);
    return $http.get('/some/data').then(function (result) {
        console.log(result); // suppose result === "xyz"
        return result;
    });
}).then(function (result){
    console.log(result); // result === xyz
}).then(function (und){
    console.log(und) // und === undefined, because of absence of return statement in above then
})

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

// Parallel http requests
promise.then(function (x) { // Suppose promise returns "abc"
    console.log(x);

    var promise1 = $http.get('/some/data?value=xyz').then(function (result) {
        console.log(result); // suppose result === "xyz"
        return result;
    });

    var promise2 = $http.get('/some/data?value=uvm').then(function (result) {
        console.log(result); // suppose result === "uvm"
        return result;
    });

    return promise1.then(function (result1) {
        return promise2.then(function (result2) {
           return { result1: result1, result2: result2; }
        });
    });
}).then(function (result){
    console.log(result); // result === { result1: 'xyz', result2: 'uvm' }
}).then(function (und){
    console.log(und) // und === undefined, because of absence of return statement in above then
})

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

// Sequential http requests
promise.then(function (x) { // Suppose promise returns "abc"
    console.log(x);

    return $http.get('/some/data?value=xyz').then(function (result1) {
        console.log(result1); // suppose result1 === "xyz"
        return $http.get('/some/data?value=uvm').then(function (result2) {
            console.log(result2); // suppose result2 === "uvm"
            return { result1: result1, result2: result2; };
        });
    });
}).then(function (result){
    console.log(result); // result === { result1: 'xyz', result2: 'uvm' }
}).then(function (und){
    console.log(und) // und === undefined, because of absence of return statement in above then
})

121
+1 สำหรับความคิดที่doneไม่ทำอะไรเลยกับผลลัพธ์ที่thenเปลี่ยนผลลัพธ์ ประเด็นใหญ่ที่คนอื่น ๆ คิดถึงคือ imo
Shanimal

9
อาจเป็นเรื่องที่ควรกล่าวถึงว่าใช้ jQuery เวอร์ชันใดเนื่องจากพฤติกรรมของการthenเปลี่ยนแปลงใน 1.8
bradley.ayers

4
+1 ตรงประเด็น ฉันสร้างตัวอย่างที่ทำงานได้หากใครต้องการที่จะเห็นสิ่งโซ่ผสมกับdoneและthenเรียกร้องให้ผลในการ.
ไมเคิล Kropat

7
ตัวอย่างข้างต้นยังแสดงให้เห็นว่างาน 'เสร็จสิ้น' บนวัตถุสัญญาเดิมที่สร้างขึ้นในขั้นต้น แต่ 'แล้ว' จะส่งคืนสัญญาใหม่
Pulak Kanti Bhattacharyya

2
สิ่งนี้ใช้ได้กับ jQuery 1.8+ รุ่นที่เก่ากว่าทำหน้าที่เหมือนdoneตัวอย่าง เปลี่ยนthenเป็นpipepre-1.8 เพื่อรับthenพฤติกรรม1.8+
David Harkness

57

.done() มีการติดต่อกลับเพียงครั้งเดียวและเป็นความสำเร็จในการติดต่อกลับ

.then() มีทั้งความสำเร็จและล้มเหลวในการโทรกลับ

.fail() มีการติดต่อกลับล้มเหลวเพียงครั้งเดียว

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


18
คุณล้มเหลวที่จะพูดถึงว่า 'แล้ว' สร้างสายการผลิต ดูคำตอบของ Lu4
oligofren

คำตอบของคุณคือจาก 2011 ... ปัจจุบันค่าการกลับมาของพวกเขาทำให้แตกต่างจากthen() done()ดังที่then()มักถูกเรียกเมื่อมีการติดต่อกลับสำเร็จคะแนนของคุณค่อนข้างมีรายละเอียดมากกว่าสิ่งสำคัญที่ต้องจำ / รู้ (ไม่สามารถบอกได้ว่ามันเป็นอย่างไรก่อน jQuery 3.0)
Robert Siemer

14

deferred.done ()

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

var url = 'http://jsonplaceholder.typicode.com/posts/1';
$.ajax(url).done(doneCallback);

function doneCallback(result) {
    console.log('Result 1 ' + result);
}

คุณสามารถเขียนด้านบนเช่นนี้

function ajaxCall() {
    var url = 'http://jsonplaceholder.typicode.com/posts/1';
    return $.ajax(url);
}

$.when(ajaxCall()).then(doneCallback, failCallback);

deferred.then ()

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

var url = 'http://jsonplaceholder.typicode.com/posts/1';
$.ajax(url).then(doneCallback, failCallback);

function doneCallback(result) {
    console.log('Result ' + result);
}

function failCallback(result) {
    console.log('Result ' + result);
}

โพสต์ของคุณไม่ชัดเจนว่าthenจะทำงานอย่างไรหากไม่มีการfailโทรกลับ - นั่นคือไม่จับfailคดีเลย
BM

กรณีที่ล้มเหลวทำให้เกิดข้อยกเว้นที่สามารถจับได้โดยระดับบนสุดของโปรแกรม คุณยังสามารถดูข้อยกเว้นในคอนโซล JavaScript
David Spector

10

จริงๆแล้วมันมีความแตกต่างที่สำคัญอย่างยิ่งตราบเท่าที่ jQuery's Deferreds ถูกสร้างขึ้นเพื่อเป็นการใช้งานของสัญญา

ความแตกต่างที่สำคัญระหว่างเสร็จแล้วนั้นคือ

  • .done() ALWAYS จะส่งกลับค่า Promise / Wraps เดียวกันกับที่เริ่มต้นด้วยไม่ว่าคุณจะทำอะไรหรือคืนอะไร
  • .then() ส่งคืนสัญญาใหม่เสมอและคุณมีหน้าที่ควบคุมว่าสัญญานั้นขึ้นอยู่กับฟังก์ชันที่คุณส่งคืน

แปลจาก jQuery เป็นภาษาท้องถิ่น ES2015 Promises .done()เป็นเหมือนการใช้โครงสร้าง "tap" รอบฟังก์ชั่นใน Promise chain ซึ่งจะเป็นการหาก chain อยู่ในสถานะ "แก้ไข" ให้ส่งค่าไปยังฟังก์ชัน .. แต่ผลลัพธ์ของฟังก์ชันนั้นจะไม่ส่งผลกระทบต่อเชนนั้น

const doneWrap = fn => x => { fn(x); return x };

Promise.resolve(5)
       .then(doneWrap( x => x + 1))
       .then(doneWrap(console.log.bind(console)));

$.Deferred().resolve(5)
            .done(x => x + 1)
            .done(console.log.bind(console));

ทั้งสองจะบันทึก 5 ไม่ใช่ 6

โปรดทราบว่าฉันใช้ Done และ doneWrap เพื่อทำการบันทึกไม่ใช่ไม่ใช่จากนั้น นั่นเป็นเพราะฟังก์ชั่น console.log ไม่ได้ส่งคืนอะไรเลย และจะเกิดอะไรขึ้นถ้าคุณผ่านไปแล้วฟังก์ชันที่ไม่ส่งคืนอะไร

Promise.resolve(5)
       .then(doneWrap( x => x + 1))
       .then(console.log.bind(console))
       .then(console.log.bind(console));

ที่จะเข้าสู่ระบบ:

5

ไม่ได้กำหนด

เกิดอะไรขึ้น? เมื่อฉันใช้. แล้วส่งผ่านฟังก์ชั่นที่ไม่ส่งคืนสิ่งใดผลลัพธ์โดยนัยคือ "ไม่ได้กำหนด" ... ซึ่งแน่นอนว่าส่งคำสัญญา [undefined] ไปยังวิธีถัดไปจากนั้นซึ่งบันทึกไว้ไม่ได้กำหนด ดังนั้นค่าดั้งเดิมที่เราเริ่มต้นจึงหายไป

.then()คือหัวใจของรูปแบบการจัดองค์ประกอบของฟังก์ชั่น: ผลลัพธ์ของแต่ละขั้นตอนจะใช้เป็นอาร์กิวเมนต์สำหรับฟังก์ชันในขั้นตอนถัดไป นั่นเป็นเหตุผลที่.. ดีที่สุดคิดว่าเป็น "tap" -> มันไม่ได้เป็นส่วนหนึ่งของการเรียบเรียง แต่เป็นสิ่งที่แอบดูค่าในขั้นตอนหนึ่งและเรียกใช้ฟังก์ชันที่ค่านั้น แต่ไม่ได้เปลี่ยนจริง องค์ประกอบใด ๆ

นี่เป็นความแตกต่างพื้นฐานที่น่าสนใจและอาจมีเหตุผลที่ดีที่ทำไมสัญญาที่เรียกว่า Native ไม่ได้ใช้วิธีการทำ. done เราไม่ต้องทราบสาเหตุว่าทำไมจึงไม่มีวิธีการ .ail เพราะมันมีความซับซ้อนมากขึ้น (เช่น. fail / .catch ไม่ใช่มิเรอร์ของ. done /. แล้ว -> ฟังก์ชั่นใน .catch ที่ส่งกลับค่าเปลือยไม่ "อยู่" ถูกปฏิเสธเหมือนที่ผ่านไปจากนั้นก็แก้ไขได้!)


6

then()เสมอหมายความว่ามันจะถูกเรียกในกรณีใด ๆ แต่พารามิเตอร์ที่ส่งผ่านนั้นแตกต่างกันใน jQuery เวอร์ชันต่างๆ

ก่อนที่จะ jQuery 1.8 เท่ากับthen() done().fail()และฟังก์ชันการเรียกกลับทั้งหมดใช้พารามิเตอร์เดียวกันร่วมกัน

แต่ ณ วันที่ jQuery 1.8 then()จะส่งคืนสัญญาใหม่และหากมีการคืนค่ามันจะถูกส่งผ่านไปยังฟังก์ชันการเรียกกลับถัดไป

ลองดูตัวอย่างต่อไปนี้:

var defer = jQuery.Deferred();

defer.done(function(a, b){
            return a + b;
}).done(function( result ) {
            console.log("result = " + result);
}).then(function( a, b ) {
            return a + b;
}).done(function( result ) {
            console.log("result = " + result);
}).then(function( a, b ) {
            return a + b;
}).done(function( result ) {
            console.log("result = " + result);
});

defer.resolve( 3, 4 );

ก่อน jQuery 1.8 คำตอบควรเป็น

result = 3
result = 3
result = 3

ทั้งหมดresultใช้เวลา 3 และthen()ฟังก์ชั่นจะส่งผ่านวัตถุที่เลื่อนออกไปเหมือนกันไปยังฟังก์ชันถัดไปเสมอ

แต่ ณ jQuery 1.8 ผลลัพธ์ควรเป็น:

result = 3
result = 7
result = NaN

เพราะเป็นครั้งแรกที่then()ฟังก์ชั่นส่งกลับสัญญาใหม่และความคุ้มค่าที่ 7 (และนี่คือพารามิเตอร์เดียวที่จะส่งต่อไป) จะถูกส่งต่อไปdone()เพื่อที่สองเขียนdone() result = 7ที่สองthen()ใช้เวลา 7 เป็นค่าaและใช้undefinedเป็นค่าbดังนั้นที่สองthen()ส่งกลับสัญญาใหม่ด้วยพารามิเตอร์ NaN และสุดท้ายdone()พิมพ์ NaN เป็นผลลัพธ์


"จากนั้น () เสมอหมายความว่ามันจะถูกเรียกในกรณีใด ๆ " - ไม่จริง ดังนั้น () จะไม่ถูกเรียกในกรณีที่เกิดข้อผิดพลาดภายในสัญญา
David Spector

ด้านที่น่าสนใจที่ a jQuery.Deferred()สามารถรับค่าได้หลายค่าซึ่งส่งผ่านไปยังค่าแรกอย่างถูกต้อง.then()- แปลกนิดหน่อยแม้ว่า ... ดังต่อไปนี้.then()ไม่สามารถทำได้ (อินเทอร์เฟซที่เลือกผ่านreturnสามารถคืนค่าได้หนึ่งค่า) native native ของ Javascript Promiseไม่ได้ทำเช่นนั้น (ซึ่งสอดคล้องกันมากขึ้นและซื่อสัตย์)
Robert Siemer


2

ใช้เท่านั้น .then()

สิ่งเหล่านี้เป็นข้อเสียของ .done()

  • ไม่สามารถถูกผูกมัด
  • บล็อกการresolve()โทร ( .done()ตัวจัดการทั้งหมดจะถูกดำเนินการซิงโครนัส)
  • resolve()อาจได้รับข้อยกเว้นจาก.done()ตัวจัดการที่ลงทะเบียน(!)
  • ข้อยกเว้นใน.done()ครึ่งฆ่าตายรอการตัดบัญชี:
    • .done()ตัวจัดการเพิ่มเติมจะถูกข้ามอย่างเงียบ ๆ

ฉันคิดว่าเป็นการชั่วคราวที่.then(oneArgOnly)จะต้องใช้เสมอ.catch()เพื่อให้ไม่มีข้อยกเว้นใด ๆ ที่จะถูกเพิกเฉยต่อความเงียบ แต่นั่นไม่เป็นความจริงอีกต่อไป: unhandledrejectionเหตุการณ์บันทึก.then()ข้อยกเว้นที่ไม่สามารถจัดการได้บนคอนโซล (เป็นค่าเริ่มต้น) สมเหตุสมผลมาก! ไม่มีเหตุผลเหลือให้ใช้.done()เลย

พิสูจน์

ข้อมูลโค้ดต่อไปนี้แสดงให้เห็นว่า:

  • .done()ตัวจัดการทั้งหมดจะถูกเรียกว่าซิงโครนัสที่จุดของresolve()
    • บันทึกเป็น 1, 3, 5, 7
    • เข้าสู่ระบบก่อนที่สคริปต์จะผ่านด้านล่าง
  • ข้อยกเว้นในผู้โทรที่ .done()มีอิทธิพลresolve()
    • เข้าสู่ระบบผ่านจับรอบ ๆ resolve()
  • ข้อยกเว้นแบ่งสัญญาจากการ.done()แก้ไข เพิ่มเติม
    • 8 และ 10 ไม่ได้เข้าสู่ระบบ!
  • .then() ไม่มีปัญหาเหล่านี้
    • บันทึกเป็น 2, 4, 6, 9, 11 หลังจากที่เธรดไม่ทำงาน
    • ( unhandledrejectionดูเหมือนว่าสภาพแวดล้อมตัวอย่างข้อมูลไม่มี)

Btw, ข้อยกเว้นจาก.done()ไม่สามารถจับได้อย่างถูกต้อง: เนื่องจากรูปแบบซิงโครนัสของ.done(), ข้อผิดพลาดจะถูกโยนที่จุด.resolve()(อาจเป็นรหัสห้องสมุด!) หรือที่.done()โทรที่แนบผู้กระทำผิดถ้ารอการแก้ไขได้รับการแก้ไขแล้ว

console.log('Start of script.');
let deferred = $.Deferred();
// deferred.resolve('Redemption.');
deferred.fail(() => console.log('fail()'));
deferred.catch(()=> console.log('catch()'));
deferred.done(() => console.log('1-done()'));
deferred.then(() => console.log('2-then()'));
deferred.done(() => console.log('3-done()'));
deferred.then(() =>{console.log('4-then()-throw');
    throw 'thrown from 4-then()';});
deferred.done(() => console.log('5-done()'));
deferred.then(() => console.log('6-then()'));
deferred.done(() =>{console.log('7-done()-throw');
    throw 'thrown from 7-done()';});
deferred.done(() => console.log('8-done()'));
deferred.then(() => console.log('9-then()'));

console.log('Resolving.');
try {
    deferred.resolve('Solution.');
} catch(e) {
    console.log(`Caught exception from handler
        in resolve():`, e);
}
deferred.done(() => console.log('10-done()'));
deferred.then(() => console.log('11-then()'));
console.log('End of script.');
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha384-vk5WoKIaW/vJyUAd9n/wmopsmNhiy+L2Z+SBxGYnUkunIxVxAv/UtMOhba/xskxh"
crossorigin="anonymous"
></script>


บางสิ่ง: 1)ฉันเห็นสิ่งที่คุณพูดว่าdoneจะไม่ถูกประหารชีวิตหากการกระทำก่อนหน้ามีข้อยกเว้น แต่ทำไมมันถึงถูกเพิกเฉยฉันหมายถึงข้อยกเว้นที่เกิดขึ้นดังนั้นทำไมคุณถึงบอกว่าเงียบ 2)ฉันดูถูกDeferredวัตถุเพราะ API ของมันทำออกมาได้แย่มาก มันซับซ้อนและสับสนเกินไป รหัสของคุณที่นี่ไม่ได้ช่วยพิสูจน์จุดของคุณและมันมีความซับซ้อนที่ไม่จำเป็นมากเกินไปสำหรับสิ่งที่คุณพยายามพิสูจน์ 3)ทำไมdoneที่ดัชนี 2, 4, 6 และดำเนินการก่อนที่ 2 then?
CodingYoshi

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

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

@ การเข้ารหัสโยชิฉันปรับปรุงคำตอบของฉันอย่างมากถ้าฉันได้รับอนุญาตให้พูด รหัสและข้อความ
Robert Siemer

1

มีความแตกต่างที่สำคัญอย่างหนึ่งของjQuery 3.0ที่สามารถนำไปสู่พฤติกรรมที่ไม่คาดคิดและไม่ได้กล่าวถึงในคำตอบก่อนหน้านี้:

พิจารณารหัสต่อไปนี้:

let d = $.Deferred();
d.done(() => console.log('then'));
d.resolve();
console.log('now');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>

สิ่งนี้จะออก:

then
now

ตอนนี้แทนที่done()ด้วยthen()ในข้อมูลโค้ดเดียวกันมาก:

var d = $.Deferred();
d.then(() => console.log('then'));
d.resolve();
console.log('now');
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>

เอาท์พุทคือตอนนี้:

now
then

ดังนั้นสำหรับการแก้ไขที่รอการแก้ไขในทันทีฟังก์ชันที่ส่งไปยังdone()จะถูกเรียกใช้ในลักษณะที่ซิงโครนัสthen()เสมอ

สิ่งนี้แตกต่างจาก jQuery รุ่นก่อนหน้าซึ่งการเรียกกลับทั้งสองเรียกว่าซิงโครนัสตามที่กล่าวไว้ในคู่มือการอัพเกรด :

การเปลี่ยนแปลงพฤติกรรมอื่นที่จำเป็นสำหรับการปฏิบัติตามสัญญา / A + คือการเรียกกลับที่เลื่อนออกไปแล้ว () จะเรียกว่าแบบอะซิงโครนัสเสมอ ก่อนหน้านี้หากมีการเพิ่มการโทรกลับ. แล้ว () ลงใน Deferred ที่ได้รับการแก้ไขหรือปฏิเสธแล้วการโทรกลับจะทำงานทันทีและพร้อมกัน


-5

.done()ยุติห่วงโซ่การสัญญาทำให้แน่ใจว่าไม่มีสิ่งใดสามารถแนบขั้นตอนต่อไปได้ ซึ่งหมายความว่าการดำเนินการสัญญา jQuery สามารถโยนจัดการข้อยกเว้นใด ๆ .fail()เนื่องจากไม่มีใครสามารถจับไปได้โดยใช้

.done()ในแง่การปฏิบัติถ้าคุณไม่ได้วางแผนที่จะแนบขั้นตอนมากขึ้นในสัญญาที่คุณควรใช้ สำหรับรายละเอียดเพิ่มเติมดูว่าทำไมต้องทำสัญญา


6
ข้อควรระวัง! คำตอบนี้จะถูกต้องสำหรับการใช้งานที่มีสัญญาหลายครั้ง แต่ไม่ใช่ jQuery ซึ่ง.done()ไม่มีบทบาทในการยกเลิก เอกสารอธิบายว่า "เนื่องจาก deferred.done () ส่งคืนวัตถุที่เลื่อนออกไปวิธีการอื่นของวัตถุที่เลื่อนออกไปสามารถถูกผูกมัดกับสิ่งนี้รวมถึงวิธีการเพิ่มเติม. do ()" .fail()ไม่ได้กล่าวถึง แต่ใช่ว่าอาจถูกล่ามโซ่ด้วย
Roamer-1888

1
ไม่ดีฉันไม่ได้ตรวจสอบ jQuery
gleb bahmutov

1
@glebbahmutov - บางทีคุณควรลบคำตอบนี้เพื่อไม่ให้คนอื่นสับสน? เพียงแค่ข้อเสนอแนะที่เป็นมิตร :)
Andrey

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