javascript - .then() 在循环期间未多次执行内部函数
问题描述
我正在编写一段实现承诺的代码。它在一个循环中,并迭代输入到页面中的图像数量。首先它应该用新图像更新画布,然后它应该运行一些代码来从画布图像中获取信息。这是我目前的功能。
这是将图像更改为输入中的下一个的原因。
function readNextImage(i) {
d = new $.Deferred();
if (fileUpload.files && fileUpload.files[i]) {
var FR = new FileReader();
FR.onload = function(e) {
fabric.Image.fromURL(e.target.result, function(img) {
img.set({
left: 0,
top: 0,
evented: false
});
img.scaleToWidth(canvas.width);
img.setCoords();
canvas.add(img);
})
var imgData = context.getImageData(0,0,canvas.width,canvas.height);
d.resolve(imgData);
};
FR.readAsDataURL(fileUpload.files[i]);
}
return d.promise();
}
这是 .then() 命令中调用的另一个函数的片段。
function read_image (imgData) {
console.log("in read_image");
data = imgData.data;
/*doing some stuff to the data object*/
console.log("here is some data output");
}
最后这里是调用这两个函数的地方
for (var image_num=0; image_num<fileUpload.files.length; image_num+=1){
console.log("loop:"+image_num);
promise = readNextImage(image_num).then(read_image);
}
因此,正在发生的事情是画布正在使用新图像进行更新,但只有在最终图像更新到画布后,当我从read_image()
函数中看到任何 console.logs 时,我才看到一个输出。这是控制台输出的示例。
loop:0
loop:1
loop:2
loop:3
loop:4
loop:5
loop:6
loop:8
in read_image
here is some data output
任何关于为什么 then() 内部的函数只被调用一次的见解将不胜感激。
解决方案
您需要使用,或声明d
为函数的本地。您可能会覆盖更高范围的内容,然后解决错误的内容。let
const
var
d
function readNextImage(i) {
var d = new $.Deferred();
//^^^
其他问题:
- FileReader 对象没有错误处理,因此任何错误都会导致您的承诺永远不会解决或拒绝。
- 在解决您的承诺之前,您无需等待
fabric.Image.fromURL()
(可能是异步的)完成。 - 如果您
if
在这里的陈述不满意if (fileUpload.files && fileUpload.files[i])
,那么您将永远不会解决或拒绝承诺。
这是清理这四个问题的尝试(无法测试代码以确保它完全正确):
function readNextImage(i) {
var d = new $.Deferred();
if (fileUpload.files && fileUpload.files[i]) {
var FR = new FileReader();
FR.onload = function(e) {
fabric.Image.fromURL(e.target.result, function(img) {
img.set({
left: 0,
top: 0,
evented: false
});
img.scaleToWidth(canvas.width);
img.setCoords();
canvas.add(img);
var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
d.resolve(imgData);
});
};
FR.onerror = function(e) {
d.reject(e);
}
// start the file reader
FR.readAsDataURL(fileUpload.files[i]);
} else {
// not sure what you want to do here, but you need to resolve or reject the promise
d.resolve()
}
return d.promise();
}
在编写具有多个尚未处理承诺的异步操作的代码时,通常最好在最低级别“承诺”每个异步操作。这样,您就可以使用 Promise 的排序和流控制以及错误处理来一致地编写所有程序逻辑(这是一个很大的优势)。在这种情况下,您可以这样做:
function readFileDataURL(f) {
return new Promise(function(resolve, reject) {
var fr = new FileReader();
fr.onload = resolve;
fr.onerror = reject;
fr.readAsDataURL(f);
});
}
function imageFromURL(data) {
return new Promise(function(resolve, reject) {
fabric.Image.fromURL(data, resolve)
});
}
function readNextImage(i) {
if (fileUpload.files && fileUpload.files[i]) {
return readFileDataURL(fileUpload.files[i]).then(function(e) {
return imageFromURL(e.target.result);
}).then(function(img) {
img.set({
left: 0,
top: 0,
evented: false
});
img.scaleToWidth(canvas.width);
img.setCoords();
canvas.add(img);
var imgData = context.getImageData(0,0,canvas.width,canvas.height);
return imgData;
});
} else {
// nothing to do here
return Promise.resolve();
}
}
请注意,您还获得了两个实用函数,它们在您可能可以在其他地方重用的 Promise 中工作。
推荐阅读
- python - 使用 python 请求进行 Web 抓取的 JWT 不记名授权
- c++ - 在 std::unique_ptr 下移动值
- python - 无法使用 selenium python 获取所有 foodpanda 商店名称
- ethereum - ERC20Capped:在合约创建期间无法读取不可变变量,这意味着它们无法在构造函数 OpenZeppelin 4 中读取
- python - 如何修复这个小时费率计算器?
- javascript - 需要一个解决方案来重定向到另一个页面,并且还必须在该页面中打开一个模式
- python - 使用 python 显示活动图
- pytorch - 我可以只对特定的输出神经元应用 softmax 吗?
- javascript - IOS WebRTC js上的黑屏
- c# - WPF Xaml C#中的视频进度条