【问题标题】:Function return map with 0 elements in Typescript/AngularTypescript / Angular中具有0个元素的函数返回映射
【发布时间】:2020-06-02 03:31:57
【问题描述】:

我是 Angular 的新手,正在开发一个示例应用程序,该应用程序接受一个属性文件作为来自 html 的输入,处理文件并使用打字稿将值存储在地图中。我可以将值存储在地图中,但无法从其他组件访问地图。

文件阅读器组件.ts

export class FileReaderComponent {
    static readFileAsMap(file: File): Map<string, string> {
        let map :Map<string, string>= new Map<string, string>();

        let fileReader = new FileReader();
        fileReader.onloadend = (e) => {
            // By lines
            let lines = fileReader.result.toString().split('\n');
            for(let line = 0; line < lines.length; line++){
                if(lines[line].startsWith('#') || 
                    lines[line].startsWith('//') ||
                    ! lines[line].includes('=') ) {
                    // invalid line - ignoring it
                    continue;
                }
                let lineArr = lines[line].split('=');
                let key = lineArr[0].trim();
                let value = lineArr[1].trim();

                map.set(key, value);
                // not checking duplicate keys to let override the config
            }
        };

        fileReader.readAsText(file);
        console.log(map);
        return map;
    }
}

在上述文件中,console.log(map) 工作正常。但是当我们在另一个组件中调用这个方法时(如下),它返回的 map 包含 0 个元素。

let config: Map<string, string> = FileReaderComponent.readFileAsMap(configFile);

【问题讨论】:

    标签: angular typescript


    【解决方案1】:

    首先,它返回带有 0 个元素的 map 的原因是因为 onloadend 是异步调用的。 readAsText 本身就是一个异步的东西,完成后会调用 onloadend。没有真正的保证(实际上几乎可以肯定不会发生)它会在 return 被执行之前调用它。

    你需要处理这种异步性,比如通过一个承诺。

    现在对于console.log 的难题来说,这不是微不足道的,那是浏览器对你耍了一点花招。它控制台记录一个引用,当您在终端中查看该引用时,它已被填充,并且浏览器“有帮助”将其显示为已填充。

    要了解我的意思,请将其粘贴到您的终端中

    function f() { 
        const x = {}; 
        console.log(x); 
        setTimeout(() => {x[1] = 2}) 
    }
    

    并调用 f(),从逻辑上讲,您会期望看到 {}。但是浏览器会耍花招,你会看到 { 1: 2 }

    【讨论】:

      【解决方案2】:

      map 变量被异步赋值。你可以尝试从函数中返回一个 observable(例如使用 RxJS Subject)。试试下面的

      static readFileAsMap(file: File): Observable<Map<string, string>> {
        const result = new Subject<Map<string, string>>();
      
        let fileReader = new FileReader();
        fileReader.onloadend = (e) => {
            // By lines
            let map: Map<string, string> = new Map<string, string>();
            let lines = fileReader.result.toString().split('\n');
            for(let line = 0; line < lines.length; line++){
                if(lines[line].startsWith('#') || 
                    lines[line].startsWith('//') ||
                    ! lines[line].includes('=') ) {
                    // invalid line - ignoring it
                    continue;
                }
                let lineArr = lines[line].split('=');
                let key = lineArr[0].trim();
                let value = lineArr[1].trim();
      
                map.set(key, value);
                // not checking duplicate keys to let override the config
            }
            result.next(map);          // <-- push value here
        };
      
        fileReader.readAsText(file);
        console.log(map);
        return result.asObservable();  // <-- return an observable
      }
      

      现在你需要订阅函数readFileAsMap()来获取值。

      let config: Map<string, string>;
      
      FileReaderComponent.readFileAsMap(configFile).subscribe(
        value => { config = value; }
      );
      

      【讨论】:

      • ``` validateConfigFile(configFile: File) { let config: Map; FileReaderComponent.readFileAsMap(configFile).subscribe(value => { console.log(value); config = value; } );控制台.log(配置);订阅中的```“value”得到了正确的值,但是“config”的值仍然是空的。我尝试过使用“promise”并且效果很好。
      • 任何依赖异步数据的语句都应该在订阅中。因为这里config 变量再次被异步赋值。
      • 知道了。谢谢。
      猜你喜欢
      • 2020-11-18
      • 2010-10-31
      • 2011-03-07
      • 1970-01-01
      • 2016-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多