2016-04-20 21 views
11

Tôi có một kịch bản mà tôi đang trả lời lời hứa. Lời hứa về cơ bản đưa ra phản hồi của yêu cầu ajax.điều gì sẽ xảy ra nếu chúng tôi không giải quyết hoặc từ chối lời hứa

Khi từ chối lời hứa, nó hiển thị hộp thoại báo lỗi có lỗi máy chủ.

Điều tôi muốn làm là khi mã phản hồi là 401, tôi không muốn giải quyết lời hứa cũng như không từ chối lời hứa (vì nó hiển thị hộp thoại báo lỗi). Tôi chỉ muốn chuyển hướng đến trang đăng nhập.

Mã của tôi trông giống như sau

function makeRequest(ur,params) { 

    return new Promise(function(resolve,reject) { 

     fetch(url,params) 
     .then((response) => { 

      let status = response.status; 

      if (status >= 200 && status < 300) { 
       response.json().then((data) => { 
        resolve(data); 
       }) 
      } 
      else { 
       if(status === 401) { 
        redirectToLoginPage(); 
       } 
       else { 
        response.json().then((error) => { 

         if (!error.message) { 
          error.message = constants.SERVER_ERROR; 
         } 
         reject({status,error}); 
        })  
       } 
      } 

     }) 
    }); 
} 

Như bạn có thể thấy nếu tình trạng này là 401, tôi đang chuyển hướng đến trang đăng nhập. Lời hứa không được giải quyết hay từ chối.

Mã này có ổn không? Hoặc có cách nào tốt hơn để thực hiện việc này không.

Cảm ơn.

Trả lời

23

Lời hứa chỉ là một đối tượng có thuộc tính trong Javascript. Không có phép thuật nào cả. Vì vậy, không giải quyết hoặc từ chối lời hứa sẽ không bao giờ thay đổi trạng thái từ "đang chờ xử lý" sang bất kỳ điều gì khác. Điều này không gây ra bất kỳ vấn đề cơ bản nào trong Javascript vì lời hứa chỉ là một đối tượng Javascript thông thường. Lời hứa sẽ vẫn thu gom rác thải (ngay cả khi vẫn đang chờ xử lý) nếu không có mã nào nhắc đến lời hứa.

Hậu quả thực sự ở đây là điều đó có ý nghĩa gì đối với người tiêu dùng của lời hứa nếu trạng thái của nó không bao giờ thay đổi? Mọi người nghe .then() để giải quyết hoặc từ chối quá trình chuyển đổi sẽ không bao giờ được gọi. Hầu hết mã sử dụng lời hứa sẽ yêu cầu họ giải quyết hoặc từ chối tại một thời điểm nào đó trong tương lai (đó là lý do tại sao lời hứa được sử dụng ngay từ đầu). Nếu không, thì mã đó thường không bao giờ kết thúc công việc của nó.

Có thể bạn có thể có một số mã khác hoàn thành công việc cho nhiệm vụ đó và lời hứa chỉ bị hủy mà không bao giờ làm điều đó. Không có vấn đề nội bộ trong Javascript nếu bạn làm theo cách đó, nhưng nó không phải là cách hứa hẹn được thiết kế để làm việc và nói chung không phải là cách người tiêu dùng hứa hẹn mong đợi họ làm việc.

Như bạn có thể thấy trạng thái là 401, tôi đang chuyển hướng đến trang đăng nhập. Hứa hẹn không được giải quyết hay từ chối.

Mã này có ổn không? Hoặc là có cách nào tốt hơn để thực hiện điều này.

Trong trường hợp cụ thể này, tất cả đều ổn và chuyển hướng là trường hợp hơi đặc biệt và duy nhất.Một chuyển hướng đến một trang trình duyệt mới sẽ hoàn toàn xóa trạng thái trang hiện tại (bao gồm tất cả trạng thái Javascript) vì vậy nó hoàn toàn tốt để có một phím tắt với chuyển hướng và chỉ để lại những thứ khác chưa được giải quyết. Hệ thống sẽ hoàn toàn khởi tạo lại trạng thái Javascript của bạn khi trang mới bắt đầu tải để mọi lời hứa vẫn đang chờ xử lý sẽ bị xóa.

+1

Như bạn đã đề cập, chuyển hướng đến trang trình duyệt mới sẽ xóa hoàn toàn trạng thái trang hiện tại (bao gồm tất cả trạng thái Javascript). Nhưng điều gì sẽ xảy ra nếu tôi đang chuyển hướng trong một ứng dụng trang đơn lẻ. Tôi đang sử dụng ReactJS. Vì vậy, sẽ không có trang trình duyệt mới, chỉ là một chế độ xem khác. Cho dù đó là hoàn toàn tốt đẹp để có một phím tắt trong trường hợp đó với chuyển hướng và chỉ để lại những thứ khác chưa được giải quyết. – Aniket

+0

@Aniket - Sau đó, đó là một trường hợp khác mà câu hỏi của bạn không mô tả. Bạn sẽ phải đảm bảo mọi thứ được làm sạch đúng cách để bạn không bị rò rỉ bộ nhớ. Tôi không biết liệu sẽ có vấn đề với điều này trong phản ứng hay không. Lần tới hãy đặt loại thông tin này vào câu hỏi của bạn. – jfriend00

+0

Đảm bảo bạn không có tham chiếu đến các hàm 'reject' và' resolve', và không chỉ dừng tham chiếu lời hứa. Sau đó, GC nên bước vào. Nếu không, nếu mã của bạn vẫn tham chiếu 'giải quyết' chẳng hạn, thì Lời hứa sẽ phải tuân thủ trong trường hợp mã của bạn từng gọi' resolve() '. Dưới đây là ví dụ về API Web có thể bị rò rỉ Promises nếu không cẩn thận: https://github.com/w3c/webcomponents/issues/674 – trusktr

5

Luôn giải quyết hoặc từ chối lời hứa. Ngay cả khi bạn không sử dụng kết quả ngay bây giờ, mặc dù điều này làm việc, đó là một thực tế rất xấu để có được thành vì lời hứa yêu để nuốt lỗi, và mã của bạn phức tạp hơn trở nên khó khăn hơn để tìm những nơi mà bạn đã không hoàn thành một lời hứa rõ ràng (cộng với bạn thậm chí sẽ không biết đó là vấn đề).

2

Nó hoạt động và không thực sự là một vấn đề, trừ khi một người gọi của makeRequest hy vọng sẽ hoàn thành. Vì vậy, bạn đang phá vỡ hợp đồng ở đó.

Thay vào đó, bạn có thể trì hoãn lời hứa hoặc (trong trường hợp này) từ chối với mã trạng thái/lỗi.

2

Như những người khác đã nói đúng là nó không thực sự là vấn đề nếu bạn không giải quyết/từ chối lời hứa. Dù sao tôi sẽ giải quyết vấn đề của bạn một chút khác nhau:

function makeRequest(ur,params) { 

    return new Promise(function(resolve,reject) { 

     fetch(url,params) 
     .then((response) => { 

      let status = response.status; 

      if (status >= 200 && status < 300) { 
       response.json().then((data) => { 
        resolve(data); 
       }) 
      } 
      else { 
       reject(response); 
      } 
     }) 
    }); 
} 

makeRequest().then(function success(data) { 
    //... 
}, function error(response) { 
    if (response.status === 401) { 
     redirectToLoginPage(); 
    } 
    else { 
     response.json().then((error) => { 
      if (!error.message) { 
       error.message = constants.SERVER_ERROR; 
      } 

      //do sth. with error 
     }); 
    } 
}); 

Điều đó có nghĩa tôi sẽ từ chối tất cả các trạng thái phản ứng xấu và sau đó xử lý này trong error handler lại makeRequest của bạn.

3

Tôi nghĩ rằng "điều gì sẽ xảy ra nếu chúng tôi không giải quyết từ chối" đã được trả lời tốt - đó là lựa chọn của bạn có thêm .then hoặc .catch hay không.

Tuy nhiên, Mã này có ổn không? Hoặc có cách nào tốt hơn để thực hiện điều này. Tôi có thể nói có hai điều:

Bạn đang quấn một Promise trong new Promise khi nó không phải là cần thiết và fetch gọi có thể thất bại, bạn nên hành động đó để phương pháp gọi điện thoại của bạn không ngồi và chờ đợi một Lời hứa sẽ không bao giờ được giải quyết.

Dưới đây là một ví dụ (Tôi nghĩ rằng điều này sẽ làm việc cho logic kinh doanh của bạn, không chắc chắn 100%):

const constants = { 
    SERVER_ERROR: "500 Server Error" 
}; 
function makeRequest(url,params) { 
    // fetch already returns a Promise itself 
    return fetch(url,params) 
     .then((response) => { 

      let status = response.status; 

      // If status is forbidden, redirect to Login & return nothing, 
      // indicating the end of the Promise chain 
      if(status === 401) { 
       redirectToLoginPage(); 
       return; 
      } 
      // If status is success, return a JSON Promise 
      if(status >= 200 && status < 300) { 
       return response.json(); 
      } 
      // If status is a failure, get the JSON Promise, 
      // map the message & status, then Reject the promise 
      return response.json() 
       .then(json => { 
       if (!json.message) { 
        json.message = constants.SERVER_ERROR; 
       } 
       return Promise.reject({status, error: json.message}); 
       }) 
     }); 
} 
// This can now be used as: 
makeRequest("http://example", {}) 
    .then(json => { 
    if(typeof json === "undefined") { 
     // Redirect request occurred 
    } 
    console.log("Success:", json); 
    }) 
    .catch(error => { 
    console.log("Error:", error.status, error.message); 
    }) 

Ngược lại, gọi mã của bạn sử dụng:

makeRequest("http://example", {}) 
    .then(info => console.log("info", info)) 
    .catch(err => console.log("error", err)); 

Sẽ không đăng bất cứ điều gì vì cuộc gọi đến http://example sẽ không thành công, nhưng trình xử lý catch sẽ không bao giờ thực thi.

+0

Tôi chỉ muốn tránh nếu (typeof json === "undefined") { // Yêu cầu chuyển hướng đã xảy ra } Lý do khiến hàm makeRequest được gọi bởi nhiều hàm khác và tôi phải thực hiện việc kiểm tra đó trong mọi hàm gọi nó. – Aniket

Các vấn đề liên quan