【问题标题】:Imported async functions don't properly resolve data导入的异步函数无法正确解析数据
【发布时间】:2018-02-17 15:48:22
【问题描述】:

背景:

我一直在使用 create-react-app 创建 React 组件,而我最近的项目需要一个服务器后端来返回数据。

我喜欢使用从“API”文件中导入的函数来模拟 API 返回的数据。

最近,我开始采用较新的 async/await 函数,主要是因为它们更易于阅读。

问题:

在我的一个组件中,我导入了这些 API 函数,我最初将它们创建为异步函数(据我了解,默认情况下,它返回一个承诺,并将通过 return 关键字解析值并通过throw关键字)。

但是,当我调试代码时,我看到它调用了异步函数,然后立即继续控制台未定义的“结果”,如果我使用 .then(res=>{console.log(res)}); 也会发生这种情况,它会立即进入 then 回调函数无需等待承诺解决。

**调用这些函数的代码:**

// I have removed all the other lines of code and left the important code
import { getVideoList } from './api';
runMe = async () => {
    let res = await getVideolist();
    console.log(res);
}
<button onClick={this.runMe}>Click Me</button>

问题是当用 Promises 包装函数的内容并使用 Promises 解析函数时,它可以正常工作。

这里是原始代码:

export let getVideoList = async () => {
    let random = Math.floor(Math.random() * 3000);
    setTimeout(() => {
        let res = [
            {
                video_ID: 3,
                video_url: 'https:google.com/3',
                video_description: 'A basic video of exercise',
                tags: ['upper-body', 'biceps', 'triceps'],
            },
            {
                video_ID: 2,
                video_url: 'https:google.com/2',
                video_description: 'A basic video of exercise',
                tags: ['upper-body', 'biceps', 'triceps'],
            },
            {
                video_ID: 1,
                video_url: 'https:google.com/1',
                video_description: 'A basic video of exercise',
                tags: ['upper-body', 'biceps', 'triceps'],
            },
        ];
        return res;
    }, random);
};
export let getTags = async () => {
    let random = Math.floor(Math.random() * 3000);
    setTimeout(() => {
        return [
            { tag_ID: 1, tagName: 'upper-body' },
            { tag_ID: 2, tagName: 'biceps' },
            { tag_ID: 3, tagName: 'triceps' },
            { tag_ID: 4, tagName: 'shoulders' },
        ];
    }, random);
};
export let getVideos = async () => {
    let random = Math.floor(Math.random() * 3000);
    setTimeout(() => {
        let res = [
            { video_ID: 3, video_url: 'https:google.com/3', video_description: 'A basic video of exercise' },
            { video_ID: 2, video_url: 'https:google.com/2', video_description: 'A basic video of exercise' },
            { video_ID: 1, video_url: 'https:google.com/1', video_description: 'A basic video of exercise' },
        ];
        return res;
    }, random);
};

下面是修改后的代码:

export let getVideoList = async () => {
    return new Promise((res, rej) => {
        let random = Math.floor(Math.random() * 3000);
        setTimeout(() => {
            res([
                {
                    video_ID: 3,
                    video_url: 'https:google.com/3',
                    video_description: 'A basic video of exercise',
                    tags: ['upper-body', 'biceps', 'triceps'],
                },
                {
                    video_ID: 2,
                    video_url: 'https:google.com/2',
                    video_description: 'A basic video of exercise',
                    tags: ['upper-body', 'biceps', 'triceps'],
                },
                {
                    video_ID: 1,
                    video_url: 'https:google.com/1',
                    video_description: 'A basic video of exercise',
                    tags: ['upper-body', 'biceps', 'triceps'],
                },
            ]);
            return res;
        }, random);
    });
};
export let getTags = async () => {
    return new Promise((res, rej) => {
        let random = Math.floor(Math.random() * 3000);
        setTimeout(() => {
            res([
                { tag_ID: 1, tagName: 'upper-body' },
                { tag_ID: 2, tagName: 'biceps' },
                { tag_ID: 3, tagName: 'triceps' },
                { tag_ID: 4, tagName: 'shoulders' },
            ]);
        }, random);
    });
};
export let getVideos = async () => {
    return new Promise((res, rej) => {
        let random = Math.floor(Math.random() * 3000);
        setTimeout(() => {
            res([
                { video_ID: 3, video_url: 'https:google.com/3', video_description: 'A basic video of exercise' },
                { video_ID: 2, video_url: 'https:google.com/2', video_description: 'A basic video of exercise' },
                { video_ID: 1, video_url: 'https:google.com/1', video_description: 'A basic video of exercise' },
            ]);
        }, random);
    });
};

我不确定为什么会发生这种情况,我已经尝试搜索并且只提出了异步使用导入的新主题。

虽然这对这个项目来说不是什么大问题,但我想为未来的项目深入了解这一点。

修改代码以使用 async/await:

const timer = ms => new Promise(res => setTimeout(res, ms));
export let getVideoList = async () => {
    let random = Math.floor(Math.random() * 3000);
    await timer(random);
    let res = [
        {
            video_ID: 3,
            video_url: 'https:google.com/3',
            video_description: 'A basic video of exercise',
            tags: ['upper-body', 'biceps', 'triceps'],
        },
        {
            video_ID: 2,
            video_url: 'https:google.com/2',
            video_description: 'A basic video of exercise',
            tags: ['upper-body', 'biceps', 'triceps'],
        },
        {
            video_ID: 1,
            video_url: 'https:google.com/1',
            video_description: 'A basic video of exercise',
            tags: ['upper-body', 'biceps', 'triceps'],
        },
    ];
    return res;
};
export let getTags = async () => {
    let random = Math.floor(Math.random() * 3000);
    await timer(random);
    return [
        { tag_ID: 1, tagName: 'upper-body' },
        { tag_ID: 2, tagName: 'biceps' },
        { tag_ID: 3, tagName: 'triceps' },
        { tag_ID: 4, tagName: 'shoulders' },
    ];
};
export let getVideos = async () => {
    let random = Math.floor(Math.random() * 3000);
    await timer(random);
    let res = [
        { video_ID: 3, video_url: 'https:google.com/3', video_description: 'A basic video of exercise' },
        { video_ID: 2, video_url: 'https:google.com/2', video_description: 'A basic video of exercise' },
        { video_ID: 1, video_url: 'https:google.com/1', video_description: 'A basic video of exercise' },
    ];
    return res;
};

修复:

问题源于试图在 setTimeout 中返回一个值。

【问题讨论】:

  • 你不能 await setTimeout (它不会返回 Promise),你需要创建一个延迟函数来返回一个 Promise 才能工作:const delay = duration =&gt; new Promise(resolve =&gt; setTimeout(resolve, duration));然后等待await delay(() =&gt; ..., random)
  • 感谢您的捕获,我已将其从 OP 中删除。但是现在你提到它,如果一个异步函数同步运行它的所有代码并且没有返回或抛出,它会自动返回 undefined,还是会(在这种情况下)等待 settimeout 并返回值?
  • 不确定我是否理解你的问题,但如果你问的是如果你在没有await 的情况下运行异步函数会返回什么:它将返回一个 Promise。
  • 对不起,让我试着澄清一下。为了解释起见,在异步函数中说我们在异步函数中没有代码,异步函数是否遍历代码,看到没有返回语句,异步函数会假设我们忘记放置返回语句然后解析并返回一些默认值价值?或者这个异步函数的返回值是否会无限期地成为一个未决的承诺?
  • 我想我现在明白了,async 只是 Promises 的语法糖——所以一个空的异步函数会为你创建一个 Promise 并解析为返回值,如果你不返回任何东西,那么你会得到一个解决 undefined (jsfiddle.net/7z960211) 的承诺。

标签: javascript async-await babeljs create-react-app ecmascript-2017


【解决方案1】:
 await setTimeout(_=>{...},random)

不会工作,因为 setTimeout 不会返回承诺。可以答应它:

 const timer = ms => new Promise( res => setTimeout(res,ms));

所以你可以这样做

async whatever(){
  await timer(1000);
  return { ... };
}

(小提示:从超时内部返回什么都不做......)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-08-08
    • 1970-01-01
    • 1970-01-01
    • 2021-02-20
    • 2017-01-13
    • 2014-06-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多