我正在努力理解 javascript 异步/同步概念。
我已经对 openlayers Layer 类进行了子类化,以便在地图中进行一些自定义渲染。实例化类的对象后,我想加载数据(来自 url 的 png 文件)并将数据保存到类变量中,然后再继续根据数据进行一些自定义 webgl 渲染。我现在已经尝试了各种各样的东西,但无法让某些东西发挥作用。我希望有人能给我一些指导,告诉我应该如何构建代码来实现这一目标。
当我在类外部加载数据时,我可以做到这一点,但只能使用固定的 url,并且我需要能够在某些事件上更改 url。
用于实例化对象并尝试运行在类变量中设置数据的函数的代码:
function update_map(time_change_event) {
const new_url = 'www.example.com/' + time_change_event.detail.key
const canvasLayer = new CanvasLayer({})
canvasLayer.getData(new_url)
map.addLayer(canvasLayer)
map.removeLayer(*oldlayer*)
}
自定义类代码:
export class CanvasLayer extends Layer {
data = null;
getData(url){
async data_promise = new Promise((resolve, reject) => {
const image = new Image();
image.onload = () => {
const canvas = document.createElement('canvas');
canvas.width = image.width;
canvas.height = image.height;
const context = canvas.getContext('2d');
context.drawImage(image, 0, 0);
const data = context.getImageData(0, 0, width, height);
resolve(data);
};
image.onerror = () => {
reject(new Error('failed to load'));
};
image.src = url;
})
this.data = await data_promise;
}
render(frameState, target){
// This is called when layer is added to map
// Doing stuff with this.data does not work because it is null
console.log(this.data) returns null
}
}
为了解释 @David 所说的内容,这里有一些与 Promise 和异步函数有关的事情。这是仅使用简单承诺的一种选择:
export class CanvasLayer extends Layer {
data = new Promise()
getData(url) {
this.data = new Promise((resolve, reject) => {
const image = new Image()
image.onload = () => {
const canvas = document.createElement('canvas')
canvas.width = image.width
canvas.height = image.height
const context = canvas.getContext('2d')
context.drawImage(image, 0, 0)
const data = context.getImageData(0, 0, width, height)
resolve(data)
}
image.onerror = () => {
reject(new Error('failed to load'))
}
image.src = url
})
}
render(frameState, target) {
this.data.then((imageData) => {
console.log('Image data:', imageData)
})
}
}
它的作用是创建一个新的 Promise 并将其存储在类中以供以后使用。当您调用 render 时,您实际上只是挂钩该 Promise 并告诉它在 Promise 解析时运行一个函数。
您还可以使函数异步并具有如下内容:
async render(frameState, target) {
let imageData = await this.data
console.log('Image data:', imageData)
}
Promise 和异步的东西在 js 中可能会变得非常混乱。但这里有一些经验法则:
await
只能在异步函数中使用(截至 2024 年,尽管这可能会随着一些新的 js 功能(如顶级等待)而改变)then
链接到它来从 Promise 中获取值;但无论哪种方式,您都需要告诉代码“只需等待该值到来,在此之前您不需要执行任何其他操作。”这里有一些关于异步函数的更多信息:异步函数-developer.mozilla.org
以及有关 Promise 的一些信息:Promise -developer.mozilla.org