【问题标题】:Loop through object in async method在异步方法中循环对象
【发布时间】:2019-10-15 12:21:30
【问题描述】:

我有一个看起来像这样的对象并存储了一些属性:

基本上,我需要遍历这个对象并获取每个键的file 属性,我稍后将在我的代码中使用这些属性来生成多个Video-React 组件。我尝试使用map() 函数,但网站会因错误而崩溃:

Parsing error: Can not use keyword 'await' outside an async function.

即使我正在使用的代码示例位于 async 函数中。

这是我的代码:

            const response = await dataProvider(GET_MANY, 'vid', { ids: videoId })
            const file = response.data;
            file.map( source => {
                var videoPosition = 0;
                var sigkey = "sigkey";
                var formBody = new FormData();
                formBody.set('ver', "1.2");
                formBody.set('key', "key");
                formBody.set('video_id', file[videoPosition].file);
                formBody.set('user_id', "1234");
                formBody.set('format', "json");
                formBody.set('ip', "");
                formBody.set('tts', "0");
                formBody.set('nonce', Math.round((new Date()).getTime() / 1000));

                var sign_fields = [formBody.get('video_id'), formBody.get('user_id'), formBody.get('ip'), formBody.get('tts'), formBody.get('ver'), formBody.get('key'), formBody.get('nonce')];
                var data = sign_fields.join(':');
                var signature = hmacsha256(data, sigkey);

                formBody.set('sig', signature);

                var formBodyStringified = new URLSearchParams(formBody).toString();

                const resJson = await fetch(Config.api.livebox, {
                    method: 'POST',
                    body: formBodyStringified,
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                    }
                }).then(res => res.json());
                const finalJsonUrl = 'https:' + resJson.hls;
                this.setState({ videoSource: finalJsonUrl });
                videoPosition++;
            });

有什么建议可以循环遍历对象吗?

提前谢谢你。

【问题讨论】:

  • 使用for of 代替地图。另外你没有使用地图的返回,所以 forEach 会更合乎逻辑。
  • 将所有代码放在一个带有关键字async的函数中。在 async 函数中,您可以使用尽可能多的 await
  • 您的await fetch 确实不会出现在async 函数中。
  • 你需要在传递给response.map的回调前面包含async关键字,我也建议你把地图放在Promise.all里面
  • @Keith 你介意发布一个例子吗?我真的不擅长循环。

标签: javascript asynchronous promise async-await


【解决方案1】:

你甚至应该在你的 map 函数中包含一个 async 标签:

file.map(async source => {
                var videoPosition = 0;
                var sigkey = "sigkey";
                var formBody = new FormData();
                formBody.set('ver', "1.2");
                formBody.set('key', "key");
                formBody.set('video_id', file[videoPosition].file);
                formBody.set('user_id', "1234");
                formBody.set('format', "json");
                formBody.set('ip', "");
                formBody.set('tts', "0");
                formBody.set('nonce', Math.round((new Date()).getTime() / 1000));

                var sign_fields = [formBody.get('video_id'), formBody.get('user_id'), formBody.get('ip'), formBody.get('tts'), formBody.get('ver'), formBody.get('key'), formBody.get('nonce')];
                var data = sign_fields.join(':');
                var signature = hmacsha256(data, sigkey);

                formBody.set('sig', signature);

                var formBodyStringified = new URLSearchParams(formBody).toString();

                const resJson = await fetch(Config.api.livebox, {
                    method: 'POST',
                    body: formBodyStringified,
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                    }
                }).then(res => res.json());

或者你可以使用Promise.all:

const fetchList = file.map(source => {
                var videoPosition = 0;
                var sigkey = "sigkey";
                var formBody = new FormData();
                formBody.set('ver', "1.2");
                formBody.set('key', "key");
                formBody.set('video_id', file[videoPosition].file);
                formBody.set('user_id', "1234");
                formBody.set('format', "json");
                formBody.set('ip', "");
                formBody.set('tts', "0");
                formBody.set('nonce', Math.round((new Date()).getTime() / 1000));

                var sign_fields = [formBody.get('video_id'), formBody.get('user_id'), formBody.get('ip'), formBody.get('tts'), formBody.get('ver'), formBody.get('key'), formBody.get('nonce')];
                var data = sign_fields.join(':');
                var signature = hmacsha256(data, sigkey);

                formBody.set('sig', signature);

                var formBodyStringified = new URLSearchParams(formBody).toString();

                const request = fetch(Config.api.livebox, {
                    method: 'POST',
                    body: formBodyStringified,
                    headers: {
                        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
                    }
                }).then(res => res.json());
return request;
 });

const resJsons = Promise.all(fetchList);
resJsons.forEach(resJson => {
                const finalJsonUrl = 'https:' + resJson.hls;
                this.setState({ videoSource: finalJsonUrl });
                ...
}

【讨论】:

  • 但请注意,这将并行执行所有映射的元素。并且还会丢失错误处理。
  • 我想这就是 PO 从代码中想要的。如果并发是一个问题,我会使用 promise.all
  • 我会使用 file.map( async (source) => { '因为我们定义了一个函数更清楚
  • 你会有更好的表现,但就像@Keith 提到的,如果管理不善,你会遇到问题。
  • 如果不努力限制并发性,这可能是相当灾难性的。
【解决方案2】:

你在这行使用await

const resJson = await fetch(Config.api.livebox) 

但不正确的用法。因为父函数是map 回调函数,它不是异步的!。

【讨论】:

    猜你喜欢
    • 2011-01-26
    • 2017-08-21
    • 1970-01-01
    • 2017-05-16
    • 2019-08-23
    • 2023-03-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多