为什么要这么做
项目背景是要在app中解决pc已实现的AI功能,接口已确定,请求方式也确定,且要实现流式输出,因此pass掉了ui.request,SSE, websocket,plus.net.XMLHttpRequest;最适合的就是和pc一样使用fetch,而怎么在app中使用fetch成为一个待解决的问题。
使用前置了解
使用renderjs要解决的问题
现在我们约定原先的script标签我们命名为appScript, 新增一个script标签我们命名为renderScript
1.怎么把appScript中的数据传给renderScript(或者不恰当的称为在appScript中执行renderScript的方法)
<template>
<!--
text标签随意,不影响页面展示即可
prop:prop随便取名,options是变量
:change:[name]:name和prop保持一致就行
renderScript:和新加的script标签的module名字一样
onChange:renderScript标签中的方法,
思路是,通过修改options,触发onChange方法
-->
<text :prop="options" :change:prop="renderScript.onChange"></text>
<!--
sendChart: 当前是appScript标签中的方法,触发当前方法,修改options值
-->
<u-input @confirm="sendChart" />
</template>
<script>
export default {
data() {
return {
options: {}
}
},
methods: {
// 被触发,修改options
sendChart() {
// some code
this.options = {
flag: Date.now(),
// 其他要传的值
}
}
}
}
</script>
<script module="renderScript" lang="renderjs">
export default {
methods: {
// options变动触发当前方法
onChange(newValue, oldValue, ownerInstance) {
// some code
}
}
}
</script>
2.怎么把renderScript中的数据传给appScript(使用ownerInstance)
<script>
export default {
methods: {
// 在renderScript中触发的方法
acceptData(data) {
// some code
}
}
}
</script>
<script module="renderScript" lang="renderjs">
export default {
methods: {
// options变动触发当前方法
onChange(newValue, oldValue, ownerInstance) {
// acceptData:要触发的在appScript中的方法
// arg:要传递的值
ownerInstance.callMethod('acceptData', arg)
}
}
}
</script>
fetch请求与流式处理
<script module="renderScript" lang="renderjs">
export default {
methods: {
onChange(newValue, oldValue, ownerInstance) {
const { headers, bodyData, chatType } = newValue
fetch('xxxx', {
method: 'POST',
headers,
body: JSON.stringify(bodyData)
}).then((response) => {
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
ownerInstance.callMethod('acceptData', { type: 'error' })
}
const reader = response.body.getReader()
const processStreamResult = (result) => {
if (result.done) {
return
}
const chunk = new TextDecoder().decode(result.value, { stream: !result.done })
const lines = chunk.split('\n') // 逐条解析后端返回数据
lines.forEach((line) => {
// 具体情况具体处理
if (line.trim().length > 0 && line.startsWith('data:')) {
const match = line.match(/^data:\s*(.*)/)
const jsonData = match[1].trim()
try {
const eventData = JSON.parse(jsonData)
// 拿到数据,去acceptData方法中处理
ownerInstance.callMethod('acceptData', { type: 'success', eventData, chatType })
} catch (e) {
console.log('Failed to parse JSON:', e);
}
}
})
return reader.read().then(processStreamResult)
}
return reader.read().then(processStreamResult)
}).catch((error) => {
console.log('error----',error)
ownerInstance.callMethod('acceptData', { type: 'error' })
})
}
}
}
</script>