2016-10-16 36 views
7

Tôi có đoạn code sau và khi nó được thực hiện, nó sẽ trả cả "từ chối" và "thành công":Tại sao cả lời gọi lại và lời gọi lại của Promise đều được gọi?

// javascript promise 
var promise = new Promise(function(resolve, reject){ 
    setTimeout(function(){reject()}, 1000) 
}); 
promise 
    .catch(function(){console.log('rejected')}) 
    .then(function(){console.log('success')}); 

bất cứ ai có thể giải thích lý do tại sao thành công được đăng nhập?

+2

'bắt' đóng vai trò giống như trong' try ... catch'. Nó bắt một sự từ chối, không chỉ chạm vào nó. Để đạt được hành vi mong đợi, bạn cần trả về một lời hứa bị từ chối từ 'catch' - hoặc tốt hơn, sử dụng một' then' duy nhất với lần gọi lại thứ hai. – estus

+0

Bạn muốn 'promise.then (function() {console.log ('success');}, function() {console.log ('reject');}) 'để có được một hoặc không bao giờ cả hai. – Bergi

+0

Xem thêm [tại sao .catch(). Catch() không chuyển tiếp ngoại lệ] (http://stackoverflow.com/questions/16371129/chained-promises-not-passing-on-rejection) – Bergi

Trả lời

9

Gọi lại then được gọi vì cuộc gọi lại catch là trước cuộc gọi, không phải sau đó. Từ chối đã được xử lý bởi catch. Nếu bạn thay đổi thứ tự (ví dụ: (promise.then(...).catch(...))), cuộc gọi lại then sẽ không được thực hiện.

MDN nói rằng phương thức .catch() "trả về lời hứa mới giải quyết cho giá trị trả về của cuộc gọi lại". Lệnh gọi lại của bạn không trả về bất kỳ thứ gì, vì vậy lời hứa được giải quyết với giá trị undefined.

8

Có ai giải thích tại sao thành công được ghi lại không?

Nói tóm lại: một .then sau một .catch trong một chuỗi Promise sẽ luôn luôn được thực thi (trừ khi nó tự có lỗi).

Lời giải thích lý thuyết

Mã của bạn thực sự chỉ là một chuỗi Promise đó là lần đầu tiên thực hiện đồng bộ cài đặt nó lên để hoàn thành không đồng bộ sau đó. Công cụ Javascript sẽ chuyển qua bất kỳ số reject() hoặc Error nào tới số .then đầu tiên xuống chuỗi bằng một cuộc gọi lại reject trong đó. Các từ chối gọi lại là chức năng thứ hai được truyền cho một .then:

.then(
function(){ 
    //handle success 
}, 
function() { 
    //handle reject() and Error 
}) 

Việc sử dụng .catch là suger chỉ là cú pháp cho:

.then(null, function() { 
    //handle reject() or Error 
}) 

Mỗi phòng trong số .then 's tự động trả về một mới Promise có thể được hành động theo sau bởi .then 's (hoặc .catch' s cũng là .then 's).

quán tưởng dòng chảy của chuỗi lời hứa của bạn

Bạn có thể hình dung dòng chảy của mã của bạn với ví dụ sau:

var step1 = new Promise (function (resolve, reject) { 

    setTimeout(reject('error in step1'), 1000); 
}) 

var step2 = step1.then(null, function() { 

    // do some error handling 
    return 'done handling errors' 
}) 

var step3 = step2.then(function() { 

    // do some other stuff after error handling 
    return 'done doing other stuff' 
}, null) 

setTimeout (function() { 

console.log ('step1: ', step1); 
console.log ('step2: ', step2); 
console.log ('step3: ', step3); 

console.log(); 
console.log ('Asynchronous code completed') 
console.log(); 
}, 2000); 

console.log ('step1: ', step1); 
console.log ('step2: ', step2); 
console.log ('step3: ', step3); 

console.log(); 
console.log ('Synchronous code completed') 
console.log(); 

mà khi chạy sẽ cho kết quả đầu ra sau trong giao diện điều khiển:

step1: Promise { <rejected> 'error in step1' } 
step2: Promise { <pending> } 
step3: Promise { <pending> } 

Synchronous code completed 

step1: Promise { <rejected> 'error in step1' } 
step2: Promise { 'done handling errors' } 
step3: Promise { 'done doing other stuff' } 

Asynchronous code completed 
Các vấn đề liên quan