2015-06-08 21 views
6

nó là một mô hình phổ biến mà chúng ta thác qua một danh sách các nguồn dữ liệu với sự thành công đầu tiên phá vỡ chuỗi như thế này:Thực hiện một dự phòng sử dụng những lời hứa

var data = getData1(); 
if (!data) data = getData2(); 
if (!data) data = getData3(); 

vân vân. nếu getDataN() chức năng là không đồng bộ, tuy nhiên, nó đưa chúng ta đến 'callback địa ngục':

var data; 
getData1(function() { 
    getData2(function() { 
     getData3(function() { alert('not found'); }) 
    }) 
}); 

nơi triển khai có thể giống như thế:

function getData1(callback) { 
    $.ajax({ 
     url: '/my/url/1/', 
     success: function(ret) { data = ret }, 
     error: callback 
    }); 
} 

... với những lời hứa Anh sẽ mong đợi để viết một cái gì đó như thế này:

$.when(getData1()) 
    .then(function (x) { data = x; }) 
    .fail(function() { return getData2(); }) 
    .then(function (x) { data = x; }) 
    .fail(function() { return getData3(); }) 
    .then(function (x) { data = x; }); 

nơi thứ hai .then thực sự đề cập đến giá trị trả về của 0 đầu tiên, đó là chính nó là một lời hứa, và điều mà tôi hiểu là bị xích vào như là đầu vào cho bước chuỗi thành công.

rõ ràng tôi sai nhưng cách viết chính xác là gì?

+0

'getData1' nên trả lại '$ .ajax' lời hứa. – hsz

+0

Suy nghĩ đầu tiên: bạn có thể tiếp tục truyền lời hứa xung quanh (như một tham số thứ hai), về thành công bạn hoàn thành lời hứa, về thất bại bạn chạy gọi lại. –

+0

Tôi nghĩ rằng bạn không thể làm điều đó trên chức năng asyncrhronous. Tại sao không sử dụng gọi lại đệ quy và đơn giản nếu khác? – dann

Trả lời

11

Trong hầu hết các thư mời hứa hẹn, bạn có thể chuỗi .fail() hoặc .catch() như trong câu trả lời @ mido22, nhưng jQuery không .fail() không xử lý lỗi như vậy. Nó được đảm bảo luôn luôn vượt qua trên lời hứa đầu vào (với trạng thái không thay đổi), mà sẽ không cho phép yêu cầu "phá vỡ" của thác nếu/khi thành công xảy ra.

Phương pháp jQuery Promise duy nhất có thể trả lại lời hứa với trạng thái khác (hoặc giá trị/lý do khác) là .then().

Vì vậy, bạn có thể viết chuỗi liên tục bị lỗi bằng cách chỉ định bước tiếp theo là trình xử lý lỗi của mỗi lần xử lý ở mỗi giai đoạn.

function getDataUntilAsyncSuccess() { 
    return $.Deferred().reject() 
     .then(null, getData1) 
     .then(null, getData2) 
     .then(null, getData3); 
} 
//The nulls ensure that success at any stage will pass straight through to the first non-null success handler. 

getDataUntilAsyncSuccess().then(function (x) { 
    //"success" data is available here as `x` 
}, function (err) { 
    console.log('not found'); 
}); 

Nhưng trong thực tế, bạn có thể thường hơn tạo ra một loạt các chức năng hoặc đối tượng dữ liệu được gọi lần lượt với sự giúp đỡ của phương pháp mảng .reduce().

Ví dụ:

var fns = [ 
    getData1, 
    getData2, 
    getData3, 
    getData4, 
    getData5 
];  

function getDataUntilAsyncSuccess(data) { 
    return data.reduce(function(promise, fn) { 
     return promise.then(null, fn); 
    }, $.Deferred().reject());// a rejected promise to get the chain started 
} 

getDataUntilAsyncSuccess(fns).then(function (x) { 
    //"success" data is available here as `x` 
}, function (err) { 
    console.log('not found'); 
}); 

Hoặc, như có lẽ là một giải pháp tốt hơn ở đây:

var urls = [ 
    '/path/1/', 
    '/path/2/', 
    '/path/3/', 
    '/path/4/', 
    '/path/5/' 
];  

function getDataUntilAsyncSuccess(data) { 
    return data.reduce(function(promise, url) { 
     return promise.then(null, function() { 
      return getData(url);// call a generalised `getData()` function that accepts a URL. 
     }); 
    }, $.Deferred().reject());// a rejected promise to get the chain started 
} 

getDataUntilAsyncSuccess(urls).then(function (x) { 
    //"success" data is available here as `x` 
}, function (err) { 
    console.log('not found'); 
}); 
+0

thật tuyệt vời @ Roamer-1888. thật hấp dẫn tôi chưa thấy bất kỳ ví dụ nào về loại giải pháp này, nhưng điều này rất sạch sẽ. Tôi sẽ chấp nhận nó như một giải pháp khi tôi đã xác minh nó hoạt động.+1 – ekkis

+0

Tôi đã trả lời tương tự nhiều lần gần đây nhưng các câu hỏi có tất cả đều không giống nhau, có lẽ là lý do tại sao chúng rất khó tìm. Bạn hầu như cần phải biết câu trả lời để biết những gì để tìm kiếm, đó là lý do tại sao tôi tiếp tục cung cấp câu trả lời mới thay vì liên kết đến trước đó. –

+1

BTW, tín dụng chuyển đến @Bergi vì đã đưa tôi vào ngay phương pháp này ngay từ đầu. Rất tiếc, hiện không có thời gian để tìm liên kết. –

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