我对javascript相当陌生。假设我有以下代码。
let sources =["http://localhost:3001/resources/black_bish",""http://localhost:3001/resources/white_bish""]
let loaded_images=0
sources.forEach(ele = > {
let img = new Image()
img.src = ele
img.onload = function () {
loaded_images=++
}
})
这里我有一个关于Javascript和并发性的问题。难道不能像处理线程时那样同时调用这两个回调吗?这里,不会有比赛条件吗?如果我要执行与"loaded_images=++"不同的操作,是否存在我应该担心的诸如操纵数据结构之类的竞争条件?
谢谢
一种方法是为加载的每个图像返回一个Promise
。这一承诺将解决,或者用外行的话来说:在满足正确条件时,无论何时加载图像,都将继续。这就像一个return
语句,但不是结束函数,而是继续下一步。
Promise.all
是promise构造函数上的一个方法,它接受一个promise数组。当数组中的所有promise都已满(意味着已调用resolve
(时,请对所有promise的值执行操作。
const loadImage = (source) => new Promise(resolve => {
let img = new Image();
img.onload = function() {
resolve(img);
};
img.src = source;
});
const whenAllImagesAreLoaded = (...sources) => Promise.all(
sources.map(source => loadImage(source));
);
whenAllImagesAreLoaded('image-1.jpg', 'image-2.jpg').then((images) => {
images.forEach(image => {
console.log(image, ' is loaded');
});
});
另一个例子是promise与async
/await
语法的组合,它们会暂停执行,直到您等待的promise得到实现。
这打开了一种可能性,例如:在加载了前一个图像之后,一个接一个地加载图像。
async function loadImagesSequentially(...sources) {
for (const source of sources) {
let image = await loadImage(source);
console.log(image, ' is loaded');
}
}
这两种方法都能让你更好地控制如何处理比赛条件,或者完全消除它们。我建议你尽可能多地实践承诺。它是JavaScript工具箱中非常强大的工具。
如果你有任何问题,请告诉我。