2015-10-20 23 views
5

Tôi đang sử dụng Oboe.js để phân tích một tập tin JSON thực sự thực sự lớnUnhandled lời hứa từ chối trong những lời hứa không đồng bộ

const promises = []; 
oboe('http://domain/my-file.js') 
    .node('items.*', item => { 
    // parseItem() returns a rejected Promise because of invalid JSON items 
    promises.push(parseItem(item)); 
    }) 
    .done(() => { 
    Promise.all(promises).then(() => { 
     doSomething(); 
    }); 
    }) 

Nhưng giao diện điều khiển trình duyệt tôi bị tràn ngập Uncaught (in promise). Điều tương tự cũng xảy ra nếu quý vị viết lời hứa trong một setTimeout() như

const promises = []; 
setTimeout(() => { 
    promises.push(Promise.reject()); 
}, 500); 
// some time in the future 
Promise.all(promises); 

Điều thực sự lạ: trình duyệt đại hành xử khác. Trong Firefox Developer Edition mọi thứ hoạt động mà không có thông báo lỗi và trong Chrome, tôi bị tràn ngập với Uncaught (in promise). Trong Chrome, bạn sẽ nhận được tin nhắn ngay lập tức nếu bạn viết Promise.reject(); mà không bị bắt. Trong Firefox và Safari không có gì xảy ra.

Vậy giải pháp cho điều này là gì? Bỏ qua tin nhắn? Tôi có nghĩa là nếu hành vi này thực sự là trong spec hứa hẹn chính thức sau đó hứa hẹn trong mã không đồng bộ không thực sự có ý nghĩa đối với tôi.

+1

Hiện tại có hai trại của những người liên quan đến lời hứa es6. Một trại (nhà phát triển chrome bao gồm) xem xét cách bạn đang sử dụng lời hứa là lạm dụng. Hành vi bạn đang trải qua không có trong đặc tả cho lời hứa mặc dù có nhiều đề xuất cho nó vì trại khác tiếp tục đẩy lùi nói rằng các trường hợp sử dụng như trường hợp của bạn có liên quan. Thật không may, một số trình duyệt được thêm vào từ chối lời hứa từ chối đăng nhập bất chấp sự thiếu thông số kỹ thuật và bất chấp việc đẩy lùi nó. –

+0

@MicahZoltu công bằng, các trại được chia ngay cả trong số các nhà phát triển Chrome. –

+0

@MicahZoltu cảm ơn bạn đã làm rõ. Tại thời điểm này nó thực sự khó hiểu mà thực hiện sẽ là một trong những quyền. – LongFlick

Trả lời

2

Sự cố Oboe của bạn dựa trên thực tế Oboe truyền JSON vào, vì vậy chúng tôi không bao giờ biết trước có bao nhiêu lời hứa vì vậy chúng tôi không thể đính kèm trách nhiệm trước Promise.all. Chúng ta có thể "khuyến khích" Oboe để có thể trả lời những lời hứa trong các phương pháp của nó.

Thông thường, tôi muốn sử dụng RxJS để tự động tạo luồng từ phương thức trình phát sự kiện và các phương thức của RxJS có thể đã trả về các lời hứa và sau đó tổng hợp nó. Tuy nhiên - vì tôi không muốn có một thư viện của bên thứ ba ở đây, và nó có giá trị giảng dạy ít hơn - chúng ta hãy thực hiện nó chính mình:

function addMap(oboe) { 
    oboe.map = function(selector, mapper){ 
    var promises = []; 
    return new Promise(function(resolve, reject){ // create a new promise 
     oboe.node(selector, function(match){ 
     var result = mapper(match); // get result 
     // signal that we're handling the rejection to make sure it's not handled. 
     result.catch(function(){}); 
     promises.push(result); 
     }); 
     oboe.fail(reject); 
     oboe.done(function(){ resolve(promises); }); 
    }); 
    }; 
} 

nào sẽ cho phép chúng tôi làm:

var o = oboe("foo"); 
addMap(o); 
o.map("items.*", item => downloadItem(item)).then(result => { 
    // handle result here 
}); 

vấn đề setTimeout của bạn là rất giả tạo. Phần lớn mọi người không viết mã trông như thế này trong thực tế - trong thực tế việc thêm một trình xử lý lỗi không đồng bộ là một trường hợp sử dụng khá hiếm khi không làm việc với một API buộc bạn làm như vậy (ví dụ như ví dụ Oboe.js).

Điều thực sự lạ: các trình duyệt hiện đại hành xử khác nhau

Điều này là do Firefox sử dụng GC để phát hiện unhandled từ chối và Chrome một bộ đếm thời gian. Đó là chi tiết triển khai - bảo đảm duy nhất bạn sẽ có là các lỗi sẽ không được ghi lại nếu được đính kèm trong microtask (đồng bộ hoặc trong một then thực hiện trên cùng một lượt).

+0

Cảm ơn bạn đã làm ví dụ. Bạn có thể chuyển nó sang bất kỳ API dựa trên gọi lại nào như trong Node.js hoặc yêu cầu AJAX đơn giản: nếu bạn gói API dựa trên lời gọi lại với lời hứa và cuộc gọi lại này được gọi trong một thời gian trong tương lai và bạn phải từ chối lời hứa, có cùng một vấn đề. Trong trường hợp của tôi, tôi gói Oboe với một lời hứa và gọi một API dựa trên cuộc gọi thứ hai và bọc nó trong một lời hứa. Lời hứa thứ hai của tôi bị từ chối và sau đó tôi nhận được lỗi ở trên.Vậy giải pháp cho việc này là gì? Thật không may tôi rất hạn chế trong hệ thống bình luận StackOverflow vì vậy tôi không thể viết quá nhiều ở đây. – LongFlick

+0

Hoặc: Tôi không thể sử dụng những lời hứa bị từ chối một thời gian trong tương lai và được xử lý bằng Promise.all(). Vấn đề chính ở đây là tôi không có một câu trả lời trực tiếp() trên lời hứa của tôi nhưng do đó trong lời hứa Promise.all() của tôi. Nếu tôi làm cho catch() trên lời hứa bên trong của tôi nó hoạt động, nhưng tôi không muốn điều đó. Tôi muốn bắt nó trong Promise.all(). Tôi tin rằng tôi không hiểu. Vì vậy, whats các giải pháp cho các API, nơi tôi đã hứa hẹn rằng các API gọi là cũng hứa hẹn nhưng không có catch() xử lý. Tất cả chúng đều có trình xử lý catch() không? Tôi nghĩ rằng Promise.all(). Catch() là chính xác những gì tôi đang tìm kiếm – LongFlick

+0

@LongFlick 'var p = Promise.reject(); p.catch (() => {});/* lưu ý chúng tôi đã không thay đổi p, nó là cùng một lời hứa, chúng tôi chỉ cần thêm một xử lý bắt * /; p.then (...);/* không còn báo cáo từ chối không được giải quyết nữa, chúng tôi đã chọn không tham gia */' –

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