Svelte中async函数处理列表时{#each}遍历报错如何解决
错误原因
所有标记为async的函数,无论内部返回什么类型的值,实际对外的返回值永远是Promise对象,不会直接返回你构造的contact_list数组。
你的代码里$: contacts_list = getContacts($contacts)这行响应式语句,最终给contacts_list赋值的是一个Pending状态的Promise,不是可遍历的数组,Svelte的{#each}语法无法遍历Promise类型值,因此抛出遍历错误。
移除async关键字后函数直接同步返回数组,所以可以正常渲染,但这种写法下函数内部无法使用await调用异步接口拉取数据库关联数据。
解决方法
你可以选任意一种适配业务场景的写法,都可以完整保留异步数据拉取逻辑:
- 方案1:初始赋值空数组,异步逻辑执行完成后再做响应式赋值
不要直接把async函数的返回值赋给模板遍历的变量,先给遍历变量设初始空数组,在异步逻辑里拿到最终结果后手动更新变量值。修正后的代码如下:
{#each contacts_list as contact} <div>{contact}</div> {/each} <script> import { contacts, user_contacts } from './data-store' // 初始给空数组,避免初始渲染时遍历报错 let contacts_list = [] // 依赖的store值变化时,自动触发异步拉取逻辑 $: { // 重置为空数组,避免旧数据残留 contacts_list = [] getContacts($contacts, $user_contacts) } async function getContacts(contactsVal, userContactsVal) { let contact_list = [] if (isIterable(userContactsVal)) { for (let contact of userContactsVal) { // 此处可正常添加await逻辑拉取数据库关联数据,例如: // const extraInfo = await fetchContactExtra(contact.id) // contact_list.push({...contact, ...extraInfo}) contact_list.push(contact); }; }; // 异步操作完成后给响应式变量赋值,自动触发视图更新 contacts_list = contact_list }; function isIterable (value) { return Symbol.iterator in Object(value); }; </script>
- 方案2:使用Svelte内置的
{#await}块处理Promise(Svelte 3.29及以上版本支持)
直接在模板层处理异步逻辑的加载、完成、报错状态,不用手动维护中间变量:
{#await contacts_promise} <div>加载中...</div> {:then contacts_list} {#each contacts_list as contact} <div>{contact}</div> {/each} {:catch error} <div>加载联系人失败:{error.message}</div> {/await} <script> import { contacts, user_contacts } from './data-store' // 依赖变化时重新生成异步Promise $: contacts_promise = getContacts($contacts, $user_contacts) async function getContacts(contactsVal, userContactsVal) { let contact_list = [] if (isIterable(userContactsVal)) { for (let contact of userContactsVal) { // 此处可正常编写await异步逻辑 contact_list.push(contact); }; }; return contact_list; }; function isIterable (value) { return Symbol.iterator in Object(value); }; </script>
注意:异步逻辑执行时要做好依赖追踪,不要在async函数里直接读取外层响应式变量/store值,最好把依赖的值作为参数传入函数,避免闭包拿到旧值导致数据不更新。
内容的提问来源于stack exchange,提问作者Psionman
相关产品推荐
相关产品推荐

