外部承诺需要等待内部嵌套承诺
Outside promise needs to wait for inner nested promise
我有这个用例,我希望在其中执行以下操作:
- 在 indexDb 中设置元数据
- 迭代图像数组
- 查看是否已经在indexDb中设置了img
- 如果是,什么也不做,如果不是,下载img
- 在 indexDb 中设置下载的 img(作为 blob)
- 最后引发所有图像处理事件
广告数据:
[{
ETag:"",
S3URL:"",
duration:30,
filename:"",
linear-gradient:"",
status:"",
timerRequired:"yes"
}]
我目前的代码:
this.Tvlocalforage.setItem('meta', newMeta).then(() => { //Step 1
for (let idx in ads) { //Step 2
this.localforage.getItem(ads[idx]['filename']).then(blob => {
if(!blob){ //Step 3
LSPromise = imgSrcToBlob(ads[idx]['S3URL'], undefined, 'Anonymous', 1).then((blob) => { //Step 4
return this.localforage.setItem(ads[idx]['filename'], blob); //Step 5
});
LSPromises.push(LSPromise);
}
});
}
}).then(() => {
if(LSPromises.length) {
Promise.all(LSPromises).then((data) => {
this.TvLSkeyCount = LSPromises.length;
this.fireLoadAssetsEvent(); //Step 6
});
}
});
我面临的问题:
设置元数据的承诺得到解决后,它直接进入 then()
块,到那时 LSPromises
是 null
。当然我明白内部嵌套的承诺还没有解决。
我试过的解决方案:
Return LSGetter 承诺稍后下载图片。这也不起作用。
我试过的代码:
this.Tvlocalforage.setItem('meta', newMeta).then(() => {
for (let idx in ads) {
let p = this.Tvlocalforage.getItem(ads[idx]['filename']);
LSPromises.push({'promise' : p, 'filename' : ads[idx]['filename'], 'url' : ads[idx]['S3URL']});
}
}).then(() => {
if(LSPromises.length){
Promise.all(LSPromises.map(obj => {
obj['promise'].then(blob => {
if(!blob){
imgSrcToBlob(obj['url'], undefined, 'Anonymous', 1).resolve(blob => {
return this.Tvlocalforage.setItem(obj['filename'], blob);
});
}
});
})).then((data) => {this.fireLoadAssetsEvent();});
}
我尝试了另外 2 种包装方法,并尝试从内部 return promise.all
下载步骤,并尝试 resolve
下载集 return promise.all
图片传给LS。但是没有用。
可能还有其他错误,但少了一个 return
:
this.Tvlocalforage.setItem('meta', newMeta).then(() => { //Step 1
for (let idx in ads) { //Step 2
LSPromises.push(this.localforage.getItem(ads[idx]['filename']).then(blob => {
if(!blob){ //Step 3
return /* added return */ imgSrcToBlob(ads[idx]['S3URL'], undefined, 'Anonymous', 1).then((blob) => { //Step 4
return this.localforage.setItem(ads[idx]['filename'], blob); //Step 5
});
// LSPromises.push(LSPromise);
}
}));
}
// }).then(() => {
if(LSPromises.length) {
return /* <<<=== */ Promise.all(LSPromises).then((data) => {
this.TvLSkeyCount = LSPromises.length;
this.fireLoadAssetsEvent(); //Step 6
});
}
});
如果从Promise.all()
返回的promise没有返回,调用者不能等待它完成。
我无法对此进行测试,但您应该尝试展平嵌套,在最外层链接 then
。您可以更多地使用 Promise.all
以便将 ad
值与已解析的值一起通过链传递:
this.Tvlocalforage.setItem('meta', newMeta).then(() => // Step 1
Promise.all(ads.map( ad => // Step 2
Promise.all(ad, this.localforage.getItem(ad.filename))
))
).then(blobs =>
blobs.filter( ([ad, blob]) => !blob ) // Step 3
).then(blobs =>
Promise.all(blobs.map( ([ad]) =>
[ad, imgSrcToBlob(ad.S3URL, undefined, 'Anonymous', 1)] // Step 4
))
).then(blobs =>
Promise.all(blobs.map( ([ad, blob]) =>
this.localforage.setItem(ad.filename, blob) // Step 5
))
).then(data => {
this.TvLSkeyCount = data.length;
this.fireLoadAssetsEvent(); // Step 6
});
摆脱 for()
循环,因为 idx
不会是你希望它在 promise 回调中的样子,因为循环将在 promise 执行之前完成
可以使用 map() 而不是使用闭包创建数组
类似于:
this.Tvlocalforage.setItem('meta', newMeta).then(() => { //Step 1
let LSPromises = ads.map(ad => {
return this.localforage.getItem(ads[idx]['filename']).then(blob => {
if (!blob) { //Step 3
return imgSrcToBlob(ad['S3URL'], undefined, 'Anonymous', 1).then((blob) => { //Step 4
return this.localforage.setItem(ad['filename'], blob); //Step 5
});
}
return null
});
});
return Promise.all(LSPromises).then((data) => {
this.TvLSkeyCount = data.filter(o => o).length;
this.fireLoadAssetsEvent(); //Step 6
// not sure what needs to be returned here
});
});
我有这个用例,我希望在其中执行以下操作:
- 在 indexDb 中设置元数据
- 迭代图像数组
- 查看是否已经在indexDb中设置了img
- 如果是,什么也不做,如果不是,下载img
- 在 indexDb 中设置下载的 img(作为 blob)
- 最后引发所有图像处理事件
广告数据:
[{
ETag:"",
S3URL:"",
duration:30,
filename:"",
linear-gradient:"",
status:"",
timerRequired:"yes"
}]
我目前的代码:
this.Tvlocalforage.setItem('meta', newMeta).then(() => { //Step 1
for (let idx in ads) { //Step 2
this.localforage.getItem(ads[idx]['filename']).then(blob => {
if(!blob){ //Step 3
LSPromise = imgSrcToBlob(ads[idx]['S3URL'], undefined, 'Anonymous', 1).then((blob) => { //Step 4
return this.localforage.setItem(ads[idx]['filename'], blob); //Step 5
});
LSPromises.push(LSPromise);
}
});
}
}).then(() => {
if(LSPromises.length) {
Promise.all(LSPromises).then((data) => {
this.TvLSkeyCount = LSPromises.length;
this.fireLoadAssetsEvent(); //Step 6
});
}
});
我面临的问题:
设置元数据的承诺得到解决后,它直接进入 then()
块,到那时 LSPromises
是 null
。当然我明白内部嵌套的承诺还没有解决。
我试过的解决方案:
Return LSGetter 承诺稍后下载图片。这也不起作用。
我试过的代码:
this.Tvlocalforage.setItem('meta', newMeta).then(() => {
for (let idx in ads) {
let p = this.Tvlocalforage.getItem(ads[idx]['filename']);
LSPromises.push({'promise' : p, 'filename' : ads[idx]['filename'], 'url' : ads[idx]['S3URL']});
}
}).then(() => {
if(LSPromises.length){
Promise.all(LSPromises.map(obj => {
obj['promise'].then(blob => {
if(!blob){
imgSrcToBlob(obj['url'], undefined, 'Anonymous', 1).resolve(blob => {
return this.Tvlocalforage.setItem(obj['filename'], blob);
});
}
});
})).then((data) => {this.fireLoadAssetsEvent();});
}
我尝试了另外 2 种包装方法,并尝试从内部 return promise.all
下载步骤,并尝试 resolve
下载集 return promise.all
图片传给LS。但是没有用。
可能还有其他错误,但少了一个 return
:
this.Tvlocalforage.setItem('meta', newMeta).then(() => { //Step 1
for (let idx in ads) { //Step 2
LSPromises.push(this.localforage.getItem(ads[idx]['filename']).then(blob => {
if(!blob){ //Step 3
return /* added return */ imgSrcToBlob(ads[idx]['S3URL'], undefined, 'Anonymous', 1).then((blob) => { //Step 4
return this.localforage.setItem(ads[idx]['filename'], blob); //Step 5
});
// LSPromises.push(LSPromise);
}
}));
}
// }).then(() => {
if(LSPromises.length) {
return /* <<<=== */ Promise.all(LSPromises).then((data) => {
this.TvLSkeyCount = LSPromises.length;
this.fireLoadAssetsEvent(); //Step 6
});
}
});
如果从Promise.all()
返回的promise没有返回,调用者不能等待它完成。
我无法对此进行测试,但您应该尝试展平嵌套,在最外层链接 then
。您可以更多地使用 Promise.all
以便将 ad
值与已解析的值一起通过链传递:
this.Tvlocalforage.setItem('meta', newMeta).then(() => // Step 1
Promise.all(ads.map( ad => // Step 2
Promise.all(ad, this.localforage.getItem(ad.filename))
))
).then(blobs =>
blobs.filter( ([ad, blob]) => !blob ) // Step 3
).then(blobs =>
Promise.all(blobs.map( ([ad]) =>
[ad, imgSrcToBlob(ad.S3URL, undefined, 'Anonymous', 1)] // Step 4
))
).then(blobs =>
Promise.all(blobs.map( ([ad, blob]) =>
this.localforage.setItem(ad.filename, blob) // Step 5
))
).then(data => {
this.TvLSkeyCount = data.length;
this.fireLoadAssetsEvent(); // Step 6
});
摆脱 for()
循环,因为 idx
不会是你希望它在 promise 回调中的样子,因为循环将在 promise 执行之前完成
可以使用 map() 而不是使用闭包创建数组
类似于:
this.Tvlocalforage.setItem('meta', newMeta).then(() => { //Step 1
let LSPromises = ads.map(ad => {
return this.localforage.getItem(ads[idx]['filename']).then(blob => {
if (!blob) { //Step 3
return imgSrcToBlob(ad['S3URL'], undefined, 'Anonymous', 1).then((blob) => { //Step 4
return this.localforage.setItem(ad['filename'], blob); //Step 5
});
}
return null
});
});
return Promise.all(LSPromises).then((data) => {
this.TvLSkeyCount = data.filter(o => o).length;
this.fireLoadAssetsEvent(); //Step 6
// not sure what needs to be returned here
});
});