Xử lý lỗi

Lưu ý

Hành vi mà bài viết này mô tả chỉ thực hiện được khi đang bật tính năng xem trước Quản lý lỗi ở cấp độ công thức thông qua phần Thiết đặt>Tính năng sắp ra mắt>Bản xem trước. Thông tin thêm: Kiểm soát các tính năng được bật

Lỗi xảy ra. Mạng ngừng hoạt động, bộ nhớ đầy, các giá trị không mong muốn xuất hiện. Logic của bạn cần tiếp tục hoạt động bình thường khi đối mặt với những sự cố tiềm ẩn.

Theo mặc định, lỗi truyền qua các công thức của một ứng dụng và được báo cáo cho người dùng cuối của ứng dụng đó. Bằng cách này, người dùng cuối sẽ biết được sự cố không mong muốn đã xảy ra. Họ có thể tự khắc phục sự cố bằng cách nhập một giá trị khác hoặc có thể báo cáo sự cố cho chủ sở hữu ứng dụng.

Với vai trò người tạo ứng dụng, bạn có thể kiểm soát các lỗi trong ứng dụng của mình:

  • Phát hiện và xử lý lỗi. Nếu có khả năng xảy ra lỗi, bạn có thể viết các công thức cho ứng dụng để phát hiện tình trạng lỗi và thử thực hiện lại phép tính. Người dùng cuối không cần lo lắng việc xảy ra lỗi vì người tạo đã tính đến khả năng đó. Bạn có thể thực hiện việc này bằng các hàm IfError, IsErrorIsErrorOrBlank trong một công thức.
  • Báo cáo lỗi. Nếu một lỗi không được xử lý trong công thức gặp phải lỗi, lỗi đó sẽ được đưa vào trình xử lý App.OnError. Lúc này, lỗi không còn thay thế được nữa vì lỗi đã xảy ra và nằm trong phép tính công thức. Tuy nhiên, bạn có thể sử dụng App.OnError để kiểm soát cách báo cáo lỗi cho người dùng cuối, bao gồm cả việc loại bỏ tất cả báo cáo lỗi cùng nhau. App.OnError cũng cung cấp một điểm nghẽn chung để báo cáo lỗi trên toàn bộ ứng dụng.
  • Tạo và gửi lại lỗi. Cuối cùng, bạn có thể phát hiện một tình trạng lỗi bằng logic của riêng mình, một tình trạng dành riêng cho ứng dụng của bạn. Hãy sử dụng hàm Error để tạo các lỗi tùy chỉnh. Bạn cũng có thể sử dụng hàm Error để gửi lại lỗi sau khi lỗi được truy vấn trong IfError hoặc App.OnError.

Bắt đầu

Hãy bắt đầu với một ví dụ đơn giản.

  1. Tạo một màn hình mới trong ứng dụng canvas thuộc Power Apps.
  2. Chèn một thành phần kiểm soát TextInput. Thành phần này sẽ mặc định có tên là TextInput1.
  3. Chèn một thành phần kiểm soát Label.
  4. Đặt thuộc tính Text của thành phần kiểm soát Label thành công thức
1/Value( TextInput1.Text )

Biểu ngữ lỗi hiển thị với nội dung

Chúng ta gặp lỗi vì văn bản mặc định của thành phần kiểm soát TextInput"Text input", không thể chuyển thành số. Theo mặc định, đây là dấu hiệu tích cực: người dùng cuối sẽ nhận được thông báo rằng một tính năng nào đó không hoạt động như dự kiến trong ứng dụng.

Rõ ràng, chúng ta không muốn người dùng gặp lỗi mỗi khi họ khởi động ứng dụng này. Có khả năng "Text input" không phải là giá trị mặc định phù hợp cho hộp nhập văn bản. Để khắc phục lỗi này, hãy thay đổi thuộc tính Default của thành phần kiểm soát TextInput thành:

Blank()

Biểu ngữ lỗi hiển thị với nội dung

Để xem nào, giờ chúng ta gặp một lỗi khác. Những phép toán có giá trị blank, chẳng hạn như phép chia, sẽ ép giá trị trống thành 0. Và việc đó hiện đang gây ra lỗi phép chia cho 0. Để khắc phục lỗi này, chúng ta cần quyết định hành vi thích hợp cho tình huống này trong ứng dụng này là gì. Câu trả lời có thể là để hiển thị giá trị blank khi văn bản nhập vào là giá trị blank. Chúng ta có thể thực hiện việc này bằng cách gói công thức bằng hàm IfError :

IfError( 1/Value( TextInput1.Text ), Blank() )

Không có biểu ngữ lỗi nào được hiển thị, lỗi do giá trị trống đã được thay thế bằng giá trị trống

Lúc này, lỗi được thay thế bằng một giá trị hợp lệ và biểu ngữ lỗi đã biến mất. Tuy nhiên, chúng ta có thể đã phóng đại vì IfError mà chúng ta sử dụng bao gồm tất cả lỗi, kể cả việc nhập một giá trị không hợp lệ như "hello". Chúng ta có thể giải quyết vấn đề này bằng cách điều chỉnh IfError để chỉ xử lý trường hợp phép chia cho 0 và gửi lại mọi lỗi khác:

IfError( 1/Value( TextInput1.Text ), 
         If( FirstError.Kind = ErrorKind.Div0, Blank(), Error( FirstError ) ) )

Không có biểu ngữ lỗi nào được hiển thị, lỗi cụ thể do phép chia cho số không đã được thay thế bằng một khoảng trống, nếu không lỗi sẽ được đưa ra lại

Vì vậy, hãy chạy ứng dụng và thử một số giá trị khác nhau.

Nếu chúng ta không nhập giá trị nào thì khi ứng dụng bắt đầu, không có câu trả lời nào hiển thị vì giá trị mặc định là blank, những cũng không có lỗi nào hiển thị vì IfError thay thế lỗi phép chia cho 0.

Không có câu trả lời nào được hiển thị và không có biểu ngữ báo lỗi

Nếu nhập 4, chúng ta sẽ nhận được kết quả mong đợi là 0,25:

Hiển thị 0,25 và không có biểu ngữ lỗi

Nếu nhập giá trị nào đó không hợp lệ, chẳng hạn như hello, chúng ta sẽ nhận được một biểu ngữ lỗi:

Không có giá trị nào được hiển thị và biểu ngữ lỗi được hiển thị do không thể chuyển đổi

Đây là một ví dụ giới thiệu đơn giản. Bạn có thể xử lý lỗi theo nhiều cách, tùy thuộc vào nhu cầu của ứng dụng:

  1. Thay vì hiển thị biểu ngữ lỗi, chúng ta có thể hiển thị "#Error" trong thành phần kiểm soát nhãn bằng công thức. Để các loại giá trị thay thế luôn tương thích với đối số đầu tiên của hàm IfError, chúng ra cần sử dụng hàm Text để chuyển đổi rõ ràng kết quả số thành một chuỗi văn bản.
    IfError( Text( 1/Value( TextInput1.Text ) ), 
             If( FirstError.Kind = ErrorKind.Div0, Blank(), "#Error" )
    
    Không có biểu ngữ lỗi và thay vào đó #Error được hiển thị là kết quả
  2. Thay vì bọc phiên bản cụ thể này bằng hàm IfError, chúng ta có thể viết một trình xử lý tập trung App.OnError. Chúng ta không thể thay thế chuỗi hiển thị nội dung "#Error" vì lỗi đã xảy ra và App.OnError chỉ được cung cấp để kiểm soát việc báo cáo.
    If( FirstError.Kind <> ErrorKind.Div0, Error( FirstError ) )
    

Truyền lỗi

Lỗi truyền qua các công thức giống như trong Excel. Ví dụ trong Excel, nếu ô A1 có công thức là =1/0, A1 sẽ hiển thị giá trị lỗi là #DIV0!:

Bảng tính Excel có A1=1/0 và #DIV/0! hiển thị trong ô

Nếu ô A2 tham chiếu đến A1 có công thức là =A1*2 chẳng hạn, lỗi cũng truyền qua công thức đó:

Bảng tính Excel có A2=A1*2 và #DIV/0! hiển thị trong ô

Lỗi thay thế giá trị lẽ ra đã được tính toán. Không có kết quả cho phép nhân trong ô A2, chỉ có lỗi từ phép chia trong A1.

Power Fx cũng hoạt động như vậy. Nói chung, nếu một lỗi được cung cấp dưới dạng đối số của một hàm hoặc toán tử, phép tính sẽ không thực hiện được và lỗi đầu vào sẽ truyền qua dưới dạng kết quả của phép tính. Ví dụ: Mid( Text( 1/0 ), 1, 1 ) sẽ trả về lỗi Phép chia cho 0, vì phần lớn lỗi bên trong truyền qua hàm Text và hàm Mid:

Biểu ngữ lỗi hiển thị phép toán không hợp lệ: chia cho số không

Nói chung, lỗi không truyền qua các thuộc tính kiểm soát trong Power Apps. Hãy mở rộng ví dụ trước bằng cách thêm một thành phần kiểm soát khác hiển thị nếu thuộc tính Text của nhãn đầu tiên là trạng thái lỗi:

Không có lỗi nào được hiển thị trên nhãn kiểm soát thứ hai

Nếu lỗi không truyền qua một thành phần kiểm soát thì thật tốt vì hệ thống sẽ quan sát lỗi trên đầu vào của tất cả thuộc tính kiểm soát. Lỗi sẽ không bị mất.

Hầu hết các hàm và toán tử đều tuân theo quy tắc "lỗi vào, lỗi ra", nhưng có một số trường hợp ngoại lệ. Các hàm IsError, IsErrorOrBlankIfError có chức năng xử lý lỗi để không trả về lỗi ngay cả khi có lỗi được truyền vào những hàm này.

Quan sát lỗi

Lỗi không được quan sát cho đến khi giá trị của chúng được sử dụng.

Do đó, các hàm IfSelect cũng có thể không trả về lỗi nếu có lỗi được truyền vào những hàm này. Hãy xem xét công thức If( false, 1/0, 3 ). Công thức này có lỗi phép chia cho 0, nhưng vì If không lấy nhánh đó do false nên Power Fx và Power Apps sẽ không báo cáo lỗi:

Không có biểu ngữ lỗi nào được hiển thị với hàm If trong thuộc tính Văn bản nhãn

Khi sử dụng hàm Set có lỗi, hệ thống sẽ không báo cáo lỗi tại thời điểm lỗi được đặt vào biến. Ví dụ trong Power Apps, dưới đây là một công thức trong App.OnStart đặt lỗi phép chia cho 0 vào biến x:

Không có biểu ngữ lỗi nào được hiển thị khi gọi hàm Set trong App.OnStart

Không có lỗi nào được báo cáo vì x không được tham chiếu. Tuy nhiên, thời điểm chúng ta thêm một thành phần kiểm soát nhãn và đặt thuộc tính Text của thành phần này là x, lỗi sẽ hiển thị:

Biểu ngữ lỗi hiển thị với nhãn điều khiển tham chiếu đến biến x

Bạn có thể sử dụng các hàm IfError, IsErrorIsErrorOrBlank để quan sát lỗi trong một công thức. Với những hàm này, bạn có thể trả về một giá trị thay thế, thực hiện hành động thay thế hoặc sửa đổi lỗi trước khi lỗi được phát hiện và báo cáo.

Báo cáo lỗi

Sau khi quan sát thấy lỗi, bước tiếp theo là báo cáo lỗi cho người dùng cuối.

Không giống như Excel, không phải lúc nào cũng có vị trí thuận tiện để hiển thị kết quả lỗi, vì kết quả của công thức có thể dẫn đến một thuộc tính chẳng hạn như tọa độ X và Y của thành phần kiểm soát mà không có vị trí thuận tiện để hiển thị một số văn bản. Mỗi máy chủ lưu trữ Power Fx đều kiểm soát cách hiển thị lỗi cuối cùng cho người dùng cuối mà mức độ kiểm soát của người tạo đối với quy trình này. Trong Power Apps, một biểu ngữ lỗi sẽ hiển thị và App.OnError được sử dụng để kiểm soát cách báo cáo lỗi.

Điều quan trọng cần lưu ý là App.OnError không thể thay thế lỗi giống như cách mà IfError có thể. Tại thời điểm App.OnError được thực thi, lỗi đã xảy ra và kết quả đã truyền qua các công thức khác. App.OnError chỉ kiểm soát cách báo cáo lỗi cho người dùng cuối và cung cấp một móc nối để người tạo ghi lại lỗi nếu muốn.

Các biến phạm vi FirstErrorAllErrors cung cấp thông tin ngữ cảnh về lỗi hoặc nhiều lỗi. Nội dung này cung cấp thông tin về loại lỗi và nơi phát sinh lỗi cũng như nơi quan sát thấy lỗi.

Dừng lại sau khi gặp lỗi

Công thức hành vi hỗ trợ thực hiện hành động, sửa đổi cơ sở dữ liệu và thay đổi trạng thái. Các công thức này cho phép thực hiện nhiều hành động theo trình tự bằng cách sử dụng toán tử tạo chuỗi ; (hoặc ;; tùy thuộc vào ngôn ngữ).

Ví dụ trong trường hợp này, thành phần kiểm soát lưới đang hiển thị nội dung trong bảng T. Mỗi nút chọn sẽ thay đổi trạng thái trong bảng này bằng 2 lệnh gọi Patch:

Hoạt ảnh hiển thị hai bản ghi trong bảng T được cập nhật bằng số ngẫu nhiên sau mỗi lần nhấp vào nút

Trong một công thức hành vi chuỗi, các hành động sẽ không dừng lại sau khi gặp lỗi đầu tiên. Hãy sửa đổi ví dụ của chúng ta để truyền một số chỉ mục không hợp lệ vào lệnh gọi Patch đầu tiên. Lệnh gọi Patch thứ hai vẫn tiếp tục bất chấp lỗi trước đó. Lỗi đầu tiên được báo cáo cho người dùng cuối và hiển thị dưới dạng lỗi trong Studio trên thành phần kiểm soát:

Hoạt ảnh chỉ hiển thị bản ghi thứ hai trong bảng T được cập nhật bằng số ngẫu nhiên sau mỗi lần nhấp vào nút, bản ghi đầu tiên dẫn đến lỗi

IfError có thể được sử dụng để dừng thực thi sau khi xảy ra lỗi. Tương tự như hàm If, đối số thứ ba của hàm này cung cấp một vị trí để đặt các hành động chỉ được thực thi nếu không có lỗi:

Hoạt ảnh không hiển thị bất kỳ thay đổi nào đối với bất kỳ bản ghi nào trong bảng T, vì IfError đang ngăn cản thao tác thứ hai hoàn tất sau lỗi

Nếu gặp lỗi trong một lần lặp lại của ForAll, mọi lần lặp lại còn lại sẽ không dừng lại. ForAll được thiết kế để thực hiện từng lần lặp một cách độc lập, cho phép thực hiện song song. Khi ForAll hoàn tất, một lỗi sẽ được trả về, chứa tất cả các lỗi gặp phải (bằng cách kiểm tra AllErrors trong IfError hoặc App.OnError).

Ví dụ: công thức sau đây sẽ cho kết quả ForAll trả về 2 lỗi (đối với phép chia cho 0 cho Value của 0, hai lần) và Collection sẽ có 3 bản ghi (khi Value không phải là 0): [1, 2, 3].

Clear( Collection ); 
ForAll( [1,0,2,0,3], If( 1/Value > 0, Collect( Collection, Value ) ) );

Xứ lý nhiều lỗi

Vì một công thức hành vi có thể thực thi nhiều hành động nên cũng có thể gặp nhiều lỗi.

Theo mặc định, lỗi đầu tiên được báo cáo cho người dùng cuối. Trong ví dụ dưới đây, cả hai lệnh gọi Patch đều không không thành công, lệnh gọi thứ hai có lỗi phép chia cho 0. Người dùng chỉ nhìn thấy lỗi đầu tiên (về chỉ mục):

Lỗi chỉ mục đầu tiên được hiển thị trong biểu ngữ lỗi, lỗi thứ hai không được báo cáo

Hàm IfErrorApp.OnError có thể truy cập vào tất cả các lỗi gặp phải với biến phạm vi AllErrors. Trong trường hợp này, chúng ta có thể đặt biến này thành biến toàn cục và xem xét cả hai lỗi gặp phải. Những lỗi này sẽ xuất hiện trong bảng theo đúng thứ tự mà lỗi xảy ra:

Ghi lại các lỗi vào biến toàn cục PatchErrors, tại đó chúng ta có thể thấy cả hai lỗi đều có mặt

Nhiều lỗi cũng có thể được trả về trong các công thức không phải công thức hành vi. Ví dụ: việc sử dụng hàm Patch với một loạt bản ghi cần cập nhật có thể trả về nhiều lỗi, một lỗi cho mỗi bản ghi không thành công.

Lỗi trong bảng

Như chúng ta đã thấy trước đó, lỗi có thể được lưu trữ trong các biến. Lỗi cũng có thể nằm trong trong cấu trúc dữ liệu, chẳng hạn như bảng. Đây là điều quan trọng để một lỗi trên bất kỳ bản ghi nào cũng không thể vô hiệu hóa toàn bộ bảng.

Ví dụ: hãy xem xét thành phần kiểm soát bảng dữ liệu dưới đây trong Power Apps:

Bảng dữ liệu hiển thị lỗi cho trường Reciprocal khi nhập 0, dẫn đến lỗi chia cho số không

Phép tính trong AddColumns đã gặp phải lỗi phép chia cho 0 đối với một trong các giá trị. Đối với một bản ghi đó, cột Reciprocal có giá trị lỗi (phép chia cho 0), nhưng các bản ghi khác thì không và vẫn hoạt động bình thường. IsError( Index( output, 2 ) ) trả về false và IsError( Index( output, 2 ).Value ) trả về true.

Nếu xảy ra lỗi khi lọc bảng, toàn bộ bản ghi sẽ là lỗi nhưng vẫn được trả về trong kết quả để người dùng cuối biết được nội dung và vấn đề.

Hãy xem ví dụ sau đây. Trong ví dụ này, bảng ban đầu không có lỗi, nhưng hành động lọc sẽ tạo ra lỗi mỗi khi Giá trị bằng 0:

Bảng dữ liệu hiển thị lỗi cho hai bản ghi không thể xử lý được theo tiêu chí Lọc

Giá trị -5 và -3 được lọc ra bình thường. Giá trị 0 gây ra lỗi khi xử lý bộ lọc nên không rõ liệu bản ghi có nằm trong kết quả hay không. Để tăng tối đa tính minh bạch cho người dùng cuối và giúp người tạo gỡ lỗi, chúng ta sẽ thêm một bản ghi lỗi thay cho bản ghi ban đầu. Trong trường hợp này, IsError( Index( output, 2 ) ) sẽ trả về giá trị true.

Lỗi nguồn dữ liệu

Các hàm sửa đổi dữ liệu trong nguồn dữ liệu (chẳng hạn như hàm Patch, Collect, Remove, RemoveIf, Update, UpdateIfSubmitForm) báo cáo lỗi theo 2 cách:

  • Mỗi hàm trong số này sẽ trả về một giá trị lỗi là kết quả của thao tác. Bạn có thể phát hiện lỗi bằng hàm IsError cũng như thay thế hoặc loại bỏ lỗi bằng hàm IfErrorApp.OnError như bình thường.
  • Sau khi thao tác, hàm Errors sẽ trả về lỗi cho các thao tác trước đó. Cách này có thể hữu ích khi hiển thị thông báo lỗi trên màn hình biểu mẫu mà không cần nắm bắt lỗi trong biến trạng thái.

Ví dụ: công thức dưới đây sẽ kiểm tra lỗi từ Collect và hiển thị thông báo lỗi tùy chỉnh:

IfError( Collect( Names, { Name: "duplicate" } ),
         Notify( $"OOPS: { FirstError.Message }", NotificationType.Warning ) )

Hàm Errors cũng trả về thông tin liên quan đến các lỗi trước đây trong khi thực hiện các phép tính thời gian chạy. Hàm này có thể hữu ích khi hiển thị lỗi trên màn hình biểu mẫu mà không cần nắm bắt lỗi trong biến trạng thái.

Gửi lại lỗi

Đôi khi, bạn sẽ lường trước được một một số lỗi tiềm ẩn và có thể bỏ qua những lỗi này một cách an toàn. Bên trong IfErrorApp.OnError, nếu phát hiện thấy lỗi cần được truyền cho trình xử lý cao hơn tiếp theo, bạn có thể gửi lại lỗi đó bằng Error( AllErrors ).

Tạo lỗi của riêng bạn

Bạn cũng có thể tạo lỗi của riêng mình bằng hàm Error.

Nếu đang tạo lỗi của riêng mình, bạn nên sử dụng giá trị trên 1000 để tránh xung đột tiềm ẩn với các giá trị lỗi hệ thống sau này.

Giá trị ErrorKind kiểu liệt kê

ErrorKind kiểu liệt kê Giá_trị Description
AnalysisError 18 Lỗi hệ thống. Đã xảy ra sự cố với hoạt động phân tích của trình biên dịch.
BadLanguageCode 14 Sử dụng mã ngôn ngữ không hợp lệ hoặc không xác định.
BadRegex 15 Biểu thức thông thường không hợp lệ. Hãy kiểm tra cú pháp được dùng với các hàm IsMatch, Match hoặc MatchAll.
Xung đột 6 Bản ghi đang được cập nhật đã được thay đổi tại nguồn và xung đột cần được giải quyết. Một giải pháp phổ biến là lưu bất kỳ thay đổi cục bộ nào, làm mới bản ghi và áp dụng lại những thay đổi đó.
ConstraintViolated 8 Bản ghi không vượt qua quy trình kiểm tra lỗi ràng buộc trên máy chủ.
CreatePermission 3 Người dùng không có quyền tạo bản ghi đối với nguồn dữ liệu. Ví dụ: hàm Collect đã được gọi.
DeletePermissions 5 Người dùng không có quyền xóa bản ghi đối với nguồn dữ liệu. Ví dụ: hàm Remove đã được gọi.
Div0 13 Phép chia cho 0.
EditPermissions Tệp 4 Người dùng không có quyền tạo bản ghi đối với nguồn dữ liệu. Ví dụ: hàm Patch đã được gọi.
GeneratedValue 9 Một giá trị đã được truyền nhầm vào máy chủ cho một trường mà máy chủ tự động tính toán.
InvalidFunctionUsage 16 Cách sử dụng hàm không hợp lệ. Thường thì một hoặc nhiều đối số của hàm không chính xác hoặc được sử dụng theo cách không hợp lệ.
FileNotFound 17 Không thể tìm thấy bộ nhớ SaveData.
InsufficientMemory 21 Không có đủ bộ nhớ hoặc dung lượng lưu trữ trên thiết bị để thực hiện phép tính này.
InvalidArgument 25 Một đối số không hợp lệ được truyền vào hàm.
Là nội bộ 26 Lỗi hệ thống. Đã xảy ra sự cố nội bộ với một trong các hàm.
MissingRequired 2 Thiếu một trường bắt buộc của bản ghi.
Mạng 23 Đã xảy ra sự cố với đường truyền mạng.
Không có 0 Lỗi hệ thống. Không có lỗi.
Không áp dụng 27 Không có giá trị nào. Hữu ích khi phân biệt giá trị blank có thể được coi là 0 trong các phép tính số với giá trị trống cần được gắn cờ là sự cố tiềm ẩn nếu giá trị đó được sử dụng.
NotFound 7 Không tìm thấy bản ghi. Ví dụ: bản ghi cần được sửa đổi trong hàm Patch.
NotSupported 20 Phép tính không được trình phát hoặc thiết bị này hỗ trợ.
Số 24 Một hàm số được sử dụng không đúng cách. Ví dụ: Sqrt với -1.
QuoteExceeded 22 Đã vượt quá hạn ngạch bộ nhớ.
ReadOnlyValue 10 Cột chỉ đọc được và không thể sửa đổi.
ReadPermission 19 Người dùng không có quyền đọc bản ghi đối với nguồn dữ liệu.
Đồng bộ hóa 1 Nguồn dữ liệu báo cáo lỗi. Kiểm tra cột Tin nhắn để biết thêm thông tin.
Không xác định 12 Có một lỗi nhưng không rõ loại lỗi nào.
Xác thực 11 Bản ghi không vượt qua quy trình kiểm tra xác thực.