从 finally 块调用回调函数时出现问题

Posted

技术标签:

【中文标题】从 finally 块调用回调函数时出现问题【英文标题】:Have an issue when calling a callback function from finally block 【发布时间】:2022-01-19 06:24:46 【问题描述】:

从异步函数下的 finally 块调用回调函数时遇到问题。此问题仅在将 Web 发布版本部署到 Web 服务器时发生。

要部署网络,我会执行以下操作。

    使用以下方法构建 Web 项目:flutter build web 将 Web 发布文件夹部署到真实服务器 使用 Chrome 连接到网络:https://192.168.96.102:1443/#/

我的代码如下:

import 'package:flutter/material.dart';
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;

void main() async 
  Map<String, dynamic> payload = 
    "Id": 78912,
    "Customer": "Jason Sweet",
    "Quantity": 1,
    "Price": 18.00
  ;
  print("Doing JSON POST ...");
  await request(
      "https://reqbin.com/echo/post/json",
      payload,
      (error, Map<String, dynamic> resp) 
        print(resp);
        print(resp["success"]);   
        print("xxx");
      );
  print("JSON POST Done!");
  runApp(const MyApp());


class MyApp extends StatelessWidget 
    // Codes are ommited for simple 


Future<void> request(uri, payload, callback) async 
  var _resp;
  int errorCode = -1;

  Map<String, String> _headers = 
    'Content-type': 'application/json'
  ;
  try 
    http.Response response;
    response = await http.post(
        Uri.parse(uri),
        body: json.encode(payload),
        headers: _headers).timeout(const Duration(seconds: 20));

    if (response.statusCode == 200 || response.statusCode == 204) 
      errorCode = 0;
    

    if (response.body != "") 
      try 
        _resp = (json.decode(response.body) as Map<String, dynamic>);
       catch (_) 
        try 
          _resp = (json.decode(response.body) as List<dynamic>);
         catch (_) 
          errorCode = -1;
          _resp = .cast<String, dynamic>();
        
      
    
    return;
   catch (e) 
    errorCode = -1;
   finally 
    callback(errorCode, _resp); // *** Doubt that invoke "callback" funtion in "finally" block caused issue. 
  

调用以下代码时:

  print("Doing JSON POST ...");
  await request(
      "https://reqbin.com/echo/post/json",
      payload,
      (error, Map<String, dynamic> resp) 
        print(resp);
        print(resp["success"]);    // Crashed at this line 
        print("xxx");
      );
  print("JSON POST Done!");

我希望打印以下内容:

Doing JSON POST ...
success: true
true
xxx
POST Done!

但其实输出是这样的:

main.dart.js:15357 Doing JSON POST ...
main.dart.js:1741 Fetch finished loading: GET "https://fonts.gstatic.com/s/roboto/v20/KFOmCnqEu92Fr1Me5WZLCzYlKw.ttf".
main.dart.js:15357 success: true
main.dart.js:3671 Uncaught TypeError: Cannot read properties of undefined (reading 'j')
at a_l.$2 (main.dart.js:46822)
at main.dart.js:14958
at ZL.a (main.dart.js:4846)
at ZL.$2 (main.dart.js:26907)
at YQ.$1 (main.dart.js:26901)
at XI.TZ (main.dart.js:27546)
at XI.uA (main.dart.js:27548)
at Wm.$0 (main.dart.js:27163)
at Object.nz (main.dart.js:4957)
at U.hy (main.dart.js:27087)

颤振信息:

flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel stable, 2.8.0, on Microsoft Windows [Version 10.0.19043.1348], locale en-US)
[√] android toolchain - develop for Android devices (Android SDK version 30.0.0)
[√] Chrome - develop for the web
[√] Visual Studio - develop for Windows (Visual Studio Community 2019 16.3.1)
[√] Android Studio (version 2020.3)
[√] VS Code (version 1.63.1)
[√] Connected device (3 available)

• No issues found!

谁能帮我解释一下为什么会出现这个问题?谢谢。

【问题讨论】:

_resp 在执行finally 块时不一定会初始化。此外,您应该将其声明为 Map&lt;String, dynamic&gt;? 而不是 var @jamesdlin 谢谢。使用“Map?_resp;”没有帮助。 第二个建议是正确键入变量(并避免至少需要一些强制转换)。初始化变量的第一个建议有帮助吗? 我不明白。正如我所说,使用Map&lt;String, dynamic&gt;? _resp; 不应该解决您的问题。 初始化_resp(例如var _resp = &lt;String, dynamic&gt;;)应该会有所帮助,因为这会阻止callback被未初始化的参数调用。 在我的示例代码中,代码行_resp = (json.decode(response.body) as Map&lt;String, dynamic&gt;)被正常调用,然后_resp在finally块之前被初始化。正如您在我发布的日志中看到的那样,_resp json 已经打印出来:success: true。但是,访问地图成员resp["success"] 会导致错误。那是我觉得很奇怪的事情。 【参考方案1】:

@jamesdlin 你是对的。由Map&lt;String, dynamic&gt; _resp = ; 初始化_resp 解决了这个问题。但是,我很不清楚为什么如果在 finally 块之外调用“回调”,即使没有初始化 _resp,我也不会遇到问题。以下代码可以正常工作。

Future<void> request(uri, payload, callback) async 
  var _resp;
  int errorCode = -1;

  Map<String, String> _headers = 
    'Content-type': 'application/json'
  ;
  try 
    // Omitted some codes for simple 
    // ...

    callback(errorCode, _resp);  // This calling is OK even when no initializing for _resp 
   catch (e) 
    errorCode = -1;
    callback(-1, null);
   finally 
    // callback(errorCode, _resp);  // Failed if calling in the finally block when no initializing for _resp
  

【讨论】:

以上是关于从 finally 块调用回调函数时出现问题的主要内容,如果未能解决你的问题,请参考以下文章

调用回调闭包时出现 RLMException

在 WASM-Bindgen Rust 中使用鼠标输入事件闭包创建回调时出现闭包调用错误

在 AsyncTask 中使用回调函数时出现 NullpointerException

设计一个函数,它接受不定数量的参数,这是参数都是函数。这些函数都接受一个回调函数作为参数,按照回调函数被调用的顺序返回函数名

js中的回调函数

这种优化有名称吗?