无限滚动|使用JavaScript生成器在API上分页
使用JavaScript生成器编写干净的代码
在编写前端代码时,你可能会遇到这样的情况:你必须使用分页法从API中获取所有记录。你可以将代码分解成多个函数来完成。然而,维护这么多的变量,并将状态从一个函数传递到另一个函数,并不像它看起来那么简单。数据源的异步性使得它更加复杂。然而,你可以使用async-generator函数来简化它。在这篇文章中,我将解释你如何将这个复杂的逻辑分解成简化的函数。
1.创建一个模拟的数据湖/源
为了测试这些功能,你需要一个数据源。为了模仿真实的api数据源,我将创建一个假的用户列表。
const users = Array(1000) .fill() .map((_, i) => ({ name: `user${i}`, id: `id_${i}` }));const TOTAL_RECORDS = users.length;
2.获取用户的API函数
你可以使用一个基于承诺的API函数来获取记录。然而,我将使用async-await函数来创建这个Fetch user API函数
//service.js
上面的函数fetchUsers ,需要像page 和limit 的选项。Page被定义为分页的当前页,limit被定义为要获取的记录的限制。延迟只是和1000ms的虚拟延迟,以模仿实际的网络。
3.使用生成器函数获取所有记录
传统上,你可以使用递归写一个函数来解决这个问题。然而,写递归的版本过于复杂,难以理解。你也可以使用for-loop/while-loop使用async-await。请看下面的例子。
async function main() { let records = []; let options = { page: 0, limit: 100, end: 100, total_records: Infinity };
输出
正如你所看到的,使用while-loop函数,你的主函数不得不过多地担心其他变量,如记录、分页选项。在这种情况下,生成器就会大放异彩。让我们试着把上面的例子转换为生成器。
/** * * @param {page, limit} start page index, limit/chunk of the records to fecth on each call * @default {0, 100} * @returns */async function* fetchAllRecords({ page = 0, limit = 100 } = {}) { while (true) { const records = await fetchUsers({ page: page++, limit }); yield records; if (records.done) return; }}
输出

正如你所看到的,使用生成器使代码看起来更简单,更容易阅读。
注意:如果你注意到这一行for await (let record of api) ,在这一行中,我们看到的是生成器的异步循环。这个await 信号for-loop ,api 对象是异步迭代器函数来迭代。
Codesandbox。
结论
异步等待并不能使你的API运行得更快。它只是简化了代码,增加了代码的可读性。正如某个聪明人曾经说过的。