我想在我的API中获取一些缓存数据,并执行一个DB更新查询.我已经写了代码,它运行得很好,但据我所知,它不应该运行.有人能解释一下这里的一切将如何执行吗?

const slowDbUpdate = () => {
    return new Promise((res, rej)=>{
        setTimeout(()=>{
            return res("DATA UPDATED");
        }, 10000);
    })
}

const fastCacheGet = () => {
    return new Promise((res, rej)=>{
        setTimeout(()=>{
            return res({ cache: "fast", db: "slow" });
        }, 1000);
    })
}

const test = async () => {
    try {
        slowDbUpdate().then(res => console.log(res));
        const data = await fastCacheGet();

        return data;
    } catch (error) {
        console.log("Error", error);
    }
}

编辑2: 我正在运行这个函数,我只是没有费心写下来.

test().then(res => console.log(res));

所以这就是我所理解的应该发生的事情:

  1. 函数test在调用堆栈中被推送并开始执行.
  2. JS调用slowDbUpdate函数,看到它返回promise ,将.then方法中的回调推入微任务队列.
  3. 然后,它调用fastCacheGet函数,并将其推入队列.
  4. (这是我不确定的地方)1秒过go 了,fastCacheGetPromise解析,但事件循环没有看到解析的第一个Promise,并且不调用它的回调.
  5. 10秒后,slowDbUpdate函数解析,事件循环将其回调推送到调用堆栈,然后将fastCacheGet回调推送到堆栈上,因为它已经解析.

但当我确实运行代码时,它的工作方式与我希望的一样(即返回缓存数据(编辑2:记录{ cache: "fast", db: "slow" }),并在10秒后记录"数据更新"),而不是我认为它应该的方式.我显然误解了JS的工作原理,任何帮助都是非常感谢的!

谢谢!

编辑1:我也忘了问这个,但我使用的是Node.js和Express后端.我试着做的事情从一开始就是个好主意吗?可以说,这是我第一次try 在没有完成所有工作的情况下发送回API响应.我不认为这应该是一个问题,但是如果我开始在很多API中这样做/这个API被非常频繁地调用会发生什么.我知道我必须在这样的promise 的末尾加上.catch,因为它会把应用程序当做一个未经处理的拒绝来崩溃,以防它抛给我一个错误,但还有什么会出错呢?

推荐答案

让我 comments 一下您所描述的步骤:

  1. 将函数测试推入调用堆栈并开始执行.

对,是这样

  1. JS调用slowDbUpdate函数,看到它返回promise ,将.then方法中的回调推入微任务队列.

在此阶段,微任务队列中不会放入任何内容.then回调是由Promise API注册的(作为Promise实例的私有信息).

  1. 然后,它调用fastCacheGet函数,并将其推入队列.

fastCachet将返回一个具有挂起状态的Promise实例,但此处不会将任何内容放入队列.await运算符具有以下效果:

  1. promise (由fastCacheGet返回)获取任务(作为私有信息),该任务将在await运算符下的点恢复test功能.
  2. 函数test返回(!),并且它向主程序返回未决promise .
  1. (这是我不确定的地方)1秒过go 了,fastCacheGetPromise解析,但事件循环没有看到解析的第一个Promise,并且不调用它的回调.

我认为混乱的根源可能是你认为await会阻止任何进一步的处决.但事实并非如此.test()在执行await操作符时返回,然后主程序也结束(在调用.then注册回调之后),因此事件循环可以在所有创建的promise 仍未完成的情况下愉快地完成其工作.

大约一秒钟过go 后,setTimeout回调被放入作业(job)队列(由setTimeoutAPI的主机实现),事件循环检测并执行它.对resolve的调用解析具有注册的then回调的FAST Promise,并将该回调放入微任务队列中.事件循环检测到该回调并执行它,因此大约一秒钟后您就会得到预期的输出.

10秒后,slowDbUpdate函数解析,事件循环将其回调推送到调用堆栈,然后将fastCacheGet回调推送到堆栈上,因为它已经解析.

如上所述,在暂停执行test函数时,已经执行了fastCacheGet回调.当大约10秒过go 了,执行setTimeout回调时,"慢"的promise 就解决了.它有一个挂起的函数上下文(test),因此它将其恢复放到微任务队列中.事件循环检测并执行这一点,即test执行上下文被唤醒,并且其执行继续,直到其结束.当执行它的return语句时,主promise (10秒前返回的)现在也实现了.

Javascript相关问答推荐

可以将SuperTest导入为ES 6模块吗?

同步功能在中间停止

试图为每支球队生成类似于2024/25年欧洲足联冠军联赛瑞士系统格式的独特比赛配对

如何在不使用类型化数组的情况下将32位浮点数按位转换为整值?

在JavaScript中打开和关闭弹出窗口

Vue Quill css仅应用于我的第一个Quill Editor组件+如何自定义工具栏

如何使用React渲染器放置根dis?

在JavaScript中检索一些文本

积分计算和 colored颜色 判断错误

为什么getRecord()会因为与_logger相关的错误而失败?(使用Hedera SDK)

if/else JavaScript中的条件行为

模块与独立组件

微软Edge编辑和重新发送未显示""

数字时钟在JavaScript中不动态更新

如何从URL获取令牌?

Angular 中的类型错误上不存在获取属性

无法使用单击按钮时的useState将数据从一个页面传递到另一个页面

如何在ASP.NET JavaScript中使用Google Charts API仅对绘制为负方向的条形图移动堆叠条形图标签位置

在WordPress中使用带有WPCode的Java代码片段时出现意外令牌错误

按什么顺序接收`storage`事件?