Safari加载Three.js异步资源报SyntaxError: unexpected identifier 'loadAssets'
问题原因
你遇到的Safari语法报错是顶层await特性兼容性导致的:
- 你的代码中直接在ES模块顶层编写了
const {kitchenModel,...} = await loadAssets();语句 - Safari直到15.4版本才支持顶层await特性,低于该版本的iOS/MacOS Safari都会将顶层的
await识别为非法语法,进而抛出你遇到的报错。
解决方案
将所有依赖loadAssets返回结果的逻辑,全部包裹在异步立即执行函数(IIFE)中,避免直接在模块顶层使用await。示例修改如下:
import * as THREE from "./dependencies/three.module.js"; import { loadAssets } from "./loader.js"; import gsap from "./dependencies/gsap/index.js"; // 先定义待导出的变量占位 export let burger, rapper, skater, muppie, gamer, kitchen, chef; var lastNumber; var nextNumber; // 所有依赖资源加载结果的逻辑都放入异步IIFE中 (async function init() { const {kitchenModel, burgerModel, rapperModel, skaterModel, muppieModel, gamerModel, chefModel} = await loadAssets(); function randomExcluded(lastNumber) { var n = Math.floor(Math.random() * (3-0) + 0); if (n >= lastNumber) n++; return n; } function nextModel(last){ var arr; if(last === 0){ arr = [1,2,3,4]; } else if(last === 1){ arr = [0,2,3,4]; } else if(last === 2){ arr = [0,1,3,4]; } else if(last === 3){ arr = [0,1,2,4]; } else if(last === 4){ arr = [0,1,2,3] } return arr[Math.floor(Math.random() * (3-0) + 0)] } export const modelSwitcher = (delta) =>{ var modelNumber = nextModel(lastNumber); console.log(lastNumber); console.log(modelNumber) switch(modelNumber){ case 0: burger.animate(delta); console.log('burger'); break; case 1: rapper.animate(delta); console.log('rapper'); break; case 2: skater.animate(delta); console.log('skater'); break; case 3: muppie.animate(delta); console.log('muppie'); break; case 4: gamer.animate(delta); console.log('gamer'); break; } } class Burger{ constructor(model,model_name,model_number){ this.model_number = 0; this.model = burgerModel; this.model_name = 'burger'; this.onCreate() } onCreate(){ this.model.name = this.model_name; this.model.scale.set(.25,.25,.25); this.model.position.set(1,0,-.6); } animate(delta){ const timeline = gsap.timeline({ease: "linear"}); timeline.to(this.model.position,{y:1.1,duration:.3+delta,ease:'linear'}) timeline.to(this.model.position,{z:2.2,duration:.8+delta,ease:'linear'}) timeline.to(this.model.rotation,{y:-1.5,duration:.1+delta,ease:'linear'}) timeline.to(this.model.position,{x:-1.1,duration:.8+delta,ease:'linear'}) timeline.add(()=>lastNumber=this.model_number) timeline.add(()=>{modelSwitcher(delta)}) timeline.to(this.model.rotation,{y:-3.2,duration:.1+delta,ease:'linear'}) timeline.to(this.model.position,{z:-0.6,duration:.8+delta,ease:'linear'}) timeline.to(this.model.position,{y:0,duration:.3+delta,ease:'linear'}) timeline.add(()=>{this.model.visible = false}) timeline.to(this.model.position,{x:1.12,duration:.1,ease:'linear'}) timeline.to(this.model.rotation,{y:0,duration:.1,ease:'linear'}) timeline.add(()=>{this.model.visible = true}) } add(scene){ scene.add(this.model) } } // 其余Rapper、Skater、Muppie、Gamer、Kitchen、Chef类的代码和原代码完全一致,放在IIFE内部即可 // 实例化操作放在IIFE内部,给外部导出的变量赋值 burger = new Burger(); rapper = new Rapper(); skater = new Skater(); muppie = new Muppie(); gamer = new Gamer(); kitchen = new Kitchen(); chef = new Chef(); })() export function addAssets(scene){ kitchen.add(scene); chef.add(scene); burger.add(scene); rapper.add(scene); skater.add(scene); muppie.add(scene); gamer.add(scene); } export function setIronHitbox(){ const geometry = new THREE.BoxGeometry( .7, .5, .5 ); const material = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); const mesh = new THREE.Mesh( geometry, material ); mesh.position.set(0,1,2.35); mesh.scale.set(.7,1,1) return mesh; }
如果其他模块需要依赖这些实例的加载完成状态,可以额外导出一个初始化完成的Promise,方便外部判断加载状态。
内容的提问来源于stack exchange,提问作者Antonio Serrano Martin
相关产品推荐
相关产品推荐

