2016-09-07 27 views
8

Tôi đang cố gắng tạo một hàm đệ quy bằng cách sử dụng lời hứa, nhưng dường như không thể làm cho nó đúng. Tôi đã làm việc mã mà không sử dụng lời hứa, nhưng nó sử dụng quầy và biến toàn cầu vv và không cảm thấy khá đúng, vì vậy tôi đang cố gắng viết lại và cũng tạo ra một mô-đun để tái sử dụng.Lời hứa đệ quy Javascript

Về cơ bản, chức năng được cho là nhận được một người dùng từ Active Directory và sau đó đệ quy tìm kiếm bất kỳ báo cáo trực tiếp nào và báo cáo trực tiếp của họ, v.v.

Tôi đã chơi với rất nhiều phiên bản của các chức năng, đây là hiện thời:

function loadReports(personEmail, list) { 
    return new Promise((resolve, reject) => { 
     getAccessTokenPromise() 
      .then(access_token => { 
       list.push(personEmail); 
       return makeRequest(personEmail, access_token); 
      }).then(result => { 
       if (result.value.length > 0) { 
        Promise.all(result.value.map(person => { 
         loadReports(person.userPrincipalName, list); 
        })).then(resolve()); 
       } else { 
        resolve(); 
       } 
      }) 
      .catch(e => reject(e)); 
    }); 
} 

Chức năng getAccessTokenPromise thực hiện một yêu cầu cho một access token và trả về một lời hứa cho điều đó. Chức năng makeRequest một lần nữa chỉ yêu cầu https cho người dùng và báo cáo của họ và trả về một đối tượng json với kết quả dưới dạng Lời hứa.

Bất kỳ ý tưởng nào được nhận rất nhiều. Cảm ơn nhiều. D.

+1

"nhưng nó sử dụng bộ đếm và biến toàn cục, v.v ..." --- bây giờ bạn thấy hàm số không tinh khiết và biến tự do là xấu. Đầu tiên reimplement nó để nó không dựa vào các biến từ các phạm vi bên ngoài, sau đó promisify nó. – zerkms

Trả lời

6

Để làm cho đệ quy làm việc với lời hứa, bạn thường muốn chuỗi tất cả các lời hứa đệ quy cho người gọi của họ. Để làm điều đó, bạn PHẢI trả lại bất kỳ lời hứa nào từ các trình xử lý .then() của bạn để chúng được xích vào bản gốc. Điều này cũng có xu hướng loại bỏ promise anti-pattern của bạn về việc gói một lời hứa hiện tại với lời hứa được tạo theo cách thủ công đầy những vấn đề. Dưới đây là một cách để làm điều đó:

function loadReports(personEmail, list) { 
    return getAccessTokenPromise().then(access_token => { 
     list.push(personEmail); 
     return makeRequest(personEmail, access_token); 
    }).then(result => { 
     if (result.value.length > 0) { 
      return Promise.all(result.value.map(person => { 
       return loadReports(person.userPrincipalName, list); 
      })); 
     } 
    }); 
} 

Thay đổi được thực:

  1. Thêm return trước getAccessTokenPromise() vì vậy chúng tôi đang trở về lời hứa ban đầu. Điều này cũng cho phép chúng tôi loại bỏ các new Promise() và tất cả các loại bỏ thủ công và giải quyết được tham gia vào các mô hình chống.

  2. Thêm return trước khi đệ quy loadReports(). Điều này phải được thực hiện để cho phép .map() thu thập lời hứa đó trước khi nó được chuyển đến Promise.all().

  3. Thêm return trước số Promise.all() để chuỗi được xích vào chuỗi lời hứa ban đầu.


Bạn sẽ phải chắc chắn rằng bạn không bao giờ có thể nhận được bất kỳ loại giấy cáo bạch trong các dữ liệu cơ sở dữ liệu (một lỗi trong DB tạo ra một danh sách tròn của báo cáo). Một báo cáo cho B, B báo cáo cho C, C báo cáo cho A bởi vì nếu bạn đã có điều này, sau đó mã này sẽ đi mãi mãi và không bao giờ hoàn thành (có thể cuối cùng cạn kiệt một số tài nguyên hệ thống).

Nếu đây là mã của tôi, tôi có thể tạo Tập hợp tất cả những người đã truy cập trong cơ sở dữ liệu khi tôi đi và từ chối gọi loadReports() cho bất kỳ người nào mà chúng tôi đã truy cập trước đây. Điều này sẽ làm cho nó an toàn từ tính tròn. Bạn có thể cũng muốn log() nếu bạn thấy điều kiện đó vì nó có lẽ sẽ là một lỗi cơ sở dữ liệu/tham nhũng.

+0

Cảm ơn bạn. Vâng, điều đó tốt hơn nhiều và gọn gàng hơn nhiều. Cảm ơn bạn đã giải thích quá, rất hữu ích.Tôi đã có một giải pháp làm việc với mã ban đầu của tôi bằng cách thay đổi '.then (resolve())' thành '.then (results => {resolve()}) cuối cùng; ', nhưng tôi thích giải pháp của bạn tốt hơn nhiều. Cảm ơn nhiều lần nữa. – Darren

+0

Ngoài ra, cảm ơn cho bit cuối cùng quá, không làm cho nó qua phần "mã/thay đổi được thực hiện" trước khi thử nó. Thật thú vị vì cuối cùng tôi muốn một Set khi tôi so sánh kết quả với tư cách thành viên trên một hệ thống khác, vì vậy tôi có thể giới thiệu điều đó. Thông tin đến từ http://graph.microsoft.io, vì vậy hy vọng đáng tin cậy;). – Darren

+0

@ Darren, bạn nên xem xét chỉ '.then (resolve)'. :) –

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