Nuxt3: useFetch使用过程常见一种报错
一、问题描述
先看一段代码:
<script setup>
const fetchData = async () => {const { data, error } = await useFetch('https://api.publicapis.org/entries');const { data: data2, error: error2 } = await useFetch('https://api.publicapis.org/entries');
};await fetchData(); // if you remove await the app will start, but server terminal will return same error
</script><template><div><NuxtWelcome /></div>
</template>
这段代码在不同的Nuxt版本的报错会有不同,但本质是一样的问题:
Nuxt 3.1.1:
nuxt instance unavailable

Nuxt 3.10.3:
[nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function. This is probably not a Nuxt bug. Find out more at `https://nuxt.com/docs/guide/concepts/auto-imports#vue-and-nuxt-composables`.

也可以直接访问https://stackblitz.com/edit/github-qe9ulj-opndzv?file=app.vue,在线运行代码,查看结果。
这个问题,在之前的文章《Nuxt: A composable that requires access to the Nuxt instance was called outside of a plugin…》有提到过,这次针对useFetch的使用再次遇到该问题,就再花点时间进行记录。
之所以关注到该问题,是因为对useFetch封装后,在页面setup中调用时(以某种特定的方式进行),出现了上述的错误。
为了更好的描述问题,先简单看一段能正常运行的代码:
<script setup>
const fetchData = async () => {const { data, error } = await useFetch('https://api.publicapis.org/entries');
};await fetchData(); // if you remove await the app will start, but server terminal will return same error
</script><template><div><NuxtWelcome /></div>
</template>
这段代码与之前的相比,唯一差别就是async fetchData 内只出现了一次await useFetch的调用,但它却能正常运行:

一旦async fetchData 内多了一次await useFetch调用,就直接报错了:

但如果再换另一种方式就又正常了:
<script setup>
const fetchData = async () => {const res = await Promise.all([useFetch('https://api.publicapis.org/entries'),useFetch('https://api.publicapis.org/entries'),]);
};await fetchData(); // if you remove await the app will start, but server terminal will return same error
</script><template><div><NuxtWelcome /></div>
</template>

而一旦在await Promise.all之后再添加useFetch的调用就立马又报错:

这个问题在此看似乎可以描述为:在方法内多次调用useFetch,会导致错误?
正好有一篇《Nuxt 3 useFetch - nuxt instance unavailable when using useFetch at least twice in one function》提到了这样的观点,之前的代码也是来源于此。但它的标题描述的不够准确,因为不是在方法内多次调用useFetch就一定会有问题,比如:

上面这样就很正常,那么出问题的地方就在于是否使用了await。为了验证这个想法,先只给第一个useFetch加上await:

接下来,只给第二个useFetch加上await:

至此,该问题可以描述为:在方法内一旦出现了await useFetch之后,再有useFetch的调用就会报错。
二、问题调查
前面问题描述了比较长的过程,而关于此问题也有人提到:
After calling useFetch within a function the context is lost - it should be called either directly within your setup block (in which case the context will be preserved - or you can use callWithNuxt. More info here: #14269 (comment).
在 #14269 里最后提到nuxtApp.runWithContext #23258
根据这些,可以猜测:应该是因为在useFetch在不恰当调用环境下,nuxt的context丢失,导致useFetch报错。
我们找到runWithContext的文档看看:
You are likely here because you got a “Nuxt instance unavailable” message. Please use this method sparingly, and report examples that are causing issues, so that it can ultimately be solved at the framework level.
The runWithContext method is meant to be used to call a function and give it an explicit Nuxt context. Typically, the Nuxt context is passed around implicitly and you do not need to worry about this.
However, when working with complex async/await scenarios in middleware/plugins, you can run into instances where the current instance has been unset after an async call.
该runWithContext方法旨在用于调用函数并为其提供显式 Nuxt 上下文。通常,Nuxt 上下文会隐式传递,您无需担心这一点。但是,在处理中间件/插件中的复杂async/await场景时,您可能会遇到异步调用后当前实例已取消设置的情况。
A Deeper Explanation of Context
Vue.js Composition API (and Nuxt composables similarly) work by depending on an implicit context. During the lifecycle, Vue sets the temporary instance of the current component (and Nuxt temporary instance of nuxtApp) to a global variable and unsets it in same tick. When rendering on the server side, there are multiple requests from different users and nuxtApp running in a same global context. Because of this, Nuxt and Vue immediately unset this global instance to avoid leaking a shared reference between two users or components.
Vue.js Composition API(以及类似的 Nuxt 组合函数)通过依赖隐式上下文来工作。在生命周期中,Vue 将当前组件的临时实例(以及 nuxtApp 的 Nuxt 临时实例)设置为全局变量,并在同一Tick阶段销毁。在服务器端渲染时,有来自不同用户的多个请求,并且 nuxtApp 在同一全局上下文中运行。因此,Nuxt 和 Vue 立即取消设置此全局实例,以避免泄漏两个用户或组件之间的共享引用。
里面提到in same tick,这里的tick应该是跟Node Tick类似:
event loop 的每次迭代,在nodejs 中就叫做 “Tick” 。
在Node.js中,事件循环是一个持续运行的过程,负责处理事件和执行回调函数。事件循环包含了不同的阶段,其中之一就是"tick"阶段。在每个"tick"阶段,Node.js会执行以下几个主要任务:
- 执行微任务(microtasks):在每个"tick"阶段开始时,Node.js会首先执行所有微任务队列中的任务。微任务通常包括Promise回调、process.nextTick()等。
- 执行定时器检查:Node.js会检查定时器队列,查看是否有定时器到期需要执行。如果有定时器到期,Node.js会将其回调函数放入事件队列中,等待下一个"tick"阶段执行。
- 执行IO操作:Node.js会处理已经完成的IO操作的回调函数。这包括文件读写、网络请求等异步操作的回调函数。
- 执行事件回调:Node.js会执行事件队列中的事件回调函数。这些事件可能是由网络请求、定时器、IO操作等触发的。
- 检查是否需要继续下一个"tick"阶段:在当前"tick"阶段执行完毕后,Node.js会检查是否需要继续下一个"tick"阶段。如果事件队列中还有待处理的事件,Node.js会继续执行下一个"tick"阶段。
通过这样的"tick"阶段循环,Node.js能够高效地处理异步操作和事件回调,保证应用程序的响应性和性能。
再结合有关Vue and Nuxt composables的文档介绍:
Vue and Nuxt composables
When you are using the built-in Composition API composables provided by Vue and Nuxt, be aware that many of them rely on being called in the right context.
During a component lifecycle, Vue tracks the temporary instance of the current component (and similarly, Nuxt tracks a temporary instance of nuxtApp) via a global variable, and then unsets it in same tick. This is essential when server rendering, both to avoid cross-request state pollution (leaking a shared reference between two users) and to avoid leakage between different components.
That means that (with very few exceptions) you cannot use them outside a Nuxt plugin, Nuxt route middleware or Vue setup function. On top of that, you must use them synchronously - that is, you cannot use await before calling a composable, except within
当您使用 Vue 和 Nuxt 提供的内置 Composition API 组合函数时,请注意它们中的许多都依赖于在正确的上下文中调用。
在组件生命周期中,Vue 通过全局变量跟踪当前组件的临时实例(类似地,Nuxt 跟踪nuxtApp的临时实例),然后在同一Tick阶段销毁。这在服务器渲染时至关重要,既可以避免交叉请求状态污染(泄漏两个用户之间的共享引用),又可以避免不同组件之间的泄漏。
这意味着(除了极少数例外)你不能在 Nuxt 插件、Nuxt 路由中间件或 Vue 设置函数之外使用它们。最重要的是,您必须同步使用它们 - 也就是说,您不能在组合函数前使用await关键字,除非在<script setup>块内,在使用以defineNuxtComponent方式声明的组件的setup函数内,在defineNuxtPlugin或者defineNuxtRouteMiddleware中,这些地方即使在await后我们会执行一个转换以保持同步上下文。
也就是说,在<script setup>内,直接调用useFetch,即使useFetch前面使用await关键字也能正常访问到Nuxt Context,所以这种情况下它都能正常运行,这也是你为什么看到的useFetch的使用示例大多如此的原因:

通过上述介绍,现在可以知道之前描述的种种问题产生的原因,是因为在useFetch前使用await关键字,会导致它们处于不同的Tick阶段,而无法访问Nuxt Context引起报错。
相关文章:
Nuxt3: useFetch使用过程常见一种报错
一、问题描述 先看一段代码: <script setup> const fetchData async () > {const { data, error } await useFetch(https://api.publicapis.org/entries);const { data: data2, error: error2 } await useFetch(https://api.publicapis.org/entries);…...
当代计算机语言占比分析
在当今快速发展的科技领域,计算机语言作为程序员的工具之一,扮演着至关重要的角色。随着技术的不断演进,各种编程语言层出不穷,但在实际开发中,哪些计算机语言占据主导地位?本文将对当代计算机语言的占比进…...
基于大模型和向量数据库的 RAG 示例
1 RAG 介绍 RAG是一种先进的自然语言处理方法,它结合了信息检索和文本生成技术,用于提高问答系统、聊天机器人等应用的性能。 2 RAG 的工作流程 文档加载(Document Loading) 从各种来源加载大量文档数据。这些文档…...
【C语言】比较两个字符串大小,strcmp函数
目录 一,strcmp函数 1,strcmp函数 2,函数头文件: 3,函数原型: 4,返回取值: 二,代码实现 三,小结 一,strcmp函数 1,strcmp函数 …...
深入理解与应用Keepalive机制
目录 引言 一、VRRP协议 (一)VRRP概述 1.诞生背景 2.基本理论 (二)VRRP工作原理 (三)VRRP相关术语 二、keepalive基本理论 (一)基本性能 (二)实现原…...
嵌入(embedding)概念
嵌入(embedding)在数学和相关领域中的确是指将一个数学对象在保持其某些关键性质不变的前提下,注入到一个更大或更高维的空间中。这个过程不仅仅是简单的映射,而是要求注入的对象在新空间中的表现形式能够完整反映原有对象的内在结…...
豆瓣书影音存入Notion
使用Python将图书和影视数据存放入Notion中。 🖼️介绍 环境 Python 3.10 (建议 3.11 及以上)Pycharm / Vs Code / Vs Code Studio 项目结构 │ .env │ main.py - 主函数、执行程序 │ new_book.txt - 上一次更新书籍 │ new_video.…...
Lucene 分词 示例代码
import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.analysis.TokenStream; import org...
2.18 校招 实习 内推 面经
绿*泡*泡VX: neituijunsir 交流*裙 ,内推/实习/校招汇总表格 1、自动驾驶一周资讯 - 李想回应“年终奖有点大”;智界升级为奇瑞独立事业部;小鹏汽车春节累计智驾总里程公布 自动驾驶一周资讯 - 李想回应“年终奖有点大”&…...
spring中事务失效的场景有哪些?
异常捕获处理 在方法中已经将异常捕获处理掉并没有抛出。 事务只有捕捉到了抛出的异常才可以进行处理,如果有异常业务中直接捕获处理掉没有抛出,事务是无法感知到的。 解决:在catch块throw抛出异常。 抛出检查异常 spring默认只会回滚非检…...
Visual Studio 2022之Release版本程序发送到其它计算机运行
目录 1、缺少dll 2、应用程序无法正常启动 3、This application failed to start because no Qt platform plugin could be initialized. 代码在Debug模式下正常运行,然后切换到Release模式下,也正常运行,把第三方平台的dll拷贝到exe所在…...
Xcode下载模拟器报错Could not download iOS 17.4 Simulator (21E213).
xcode14以后最小化安装包,从而将模拟器不集中在安装包中 因此xcode14至以后的版本安装后第一次启动会加载提示安装模拟器的提示框 或者根据需要到xcode中进行所需版本|平台的模拟器进行安装 Xcode > Settings > Platforms 问题来了尝试多次都安装失败例如…...
mac在终端设置代理
前言 本篇文章介绍如何在mac终端设置代理服务器,有时候,我们需要在终端进行外网的资源访问,比如我构建v8引擎项目的时候,需要使用gclient更新组件和下载构建工具。如果单单设置了计算机的代理,依然是无法下载资源的&a…...
傅立叶之美:深入研究傅里叶分析背后的原理和数学
一、说明 T傅里叶级数及其伴随的推导是数学在现实世界中最迷人的应用之一。我一直主张通过理解数学来理解我们周围的世界。从使用线性代数设计神经网络,从混沌理论理解太阳系,到弦理论理解宇宙的基本组成部分,数学无处不在。 当然,…...
golang学习随便记16-反射
为什么需要反射 下面的例子中编写一个 Sprint 函数,只有1个参数(类型不定),返回和 fmt.Fprintf 类似的格式化后的字符串。实现方法大致为:如果参数类型本身实现了 String() 方法,那调用 String() 方法即可…...
识别恶意IP地址的有效方法
在互联网的环境中,恶意IP地址可能会对网络安全造成严重威胁,例如发起网络攻击、传播恶意软件等。因此,识别恶意IP地址是保护网络安全的重要一环。IP数据云将探讨一些有效的方法来识别恶意IP地址。 IP地址查询:https://www.ipdata…...
探索信号处理:低通滤波器的原理与应用
在信号处理领域,滤波器的应用至关重要,它能够帮助我们从复杂的信号中提取需要的信息,而低通滤波器则是其中一种被广泛应用的滤波器类型。本文旨在深入探讨低通滤波器的基本原理、主要类型以及在实际应用中的作用和实现方式。 ### 1. 低通滤波…...
计算机网络:应用层知识点汇总
文章目录 一、网络应用模型二、域名系统(DNS)三、文本传输协议(FTP)四、电子邮件五、万维网和HTTP协议 一、网络应用模型 p2p也就是对等模型 二、域名系统(DNS) 我们知道,随着人们建立一个网站…...
金三银四!一个年薪160W+的就业方向!
前言 随着越来越多的科技大厂加入鸿蒙生态建设,鸿蒙开发人才正在市场上被争抢。资深工程师开出的年薪高达近百万,架构师更是高至160万,真可谓“鸿蒙猿年薪超百万”。如何抓住新技术红利,尽早上车?你会成为下一个鸿蒙开…...
实现的一个网页版的简易表白墙
实现的一个网页版的表白墙 实现效果 代码截图 相关代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><tit…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
【SpringBoot自动化部署】
SpringBoot自动化部署方法 使用Jenkins进行持续集成与部署 Jenkins是最常用的自动化部署工具之一,能够实现代码拉取、构建、测试和部署的全流程自动化。 配置Jenkins任务时,需要添加Git仓库地址和凭证,设置构建触发器(如GitHub…...
C++--string的模拟实现
一,引言 string的模拟实现是只对string对象中给的主要功能经行模拟实现,其目的是加强对string的底层了解,以便于在以后的学习或者工作中更加熟练的使用string。本文中的代码仅供参考并不唯一。 二,默认成员函数 string主要有三个成员变量,…...
echarts使用graphic强行给图增加一个边框(边框根据自己的图形大小设置)- 适用于无法使用dom的样式
pdf-lib https://blog.csdn.net/Shi_haoliu/article/details/148157624?spm1001.2014.3001.5501 为了完成在pdf中导出echarts图,如果边框加在dom上面,pdf-lib导出svg的时候并不会导出边框,所以只能在echarts图上面加边框 grid的边框是在图里…...
