怎么用 Promise 让所有 GM_xmlhttpRequest 完成再进行下一步操作?
本帖最后由 ThisAV 于 2022-1-25 14:04 编辑https://www.xiurenji.net/XiuRen/5409.html
//获取图片生成
let currentPageID=location.href.match(/(\d+)(?:_\d+)?.html/),
pageMax=$('.page>a:last').text()=='下页'?$('.page>a:last').prev().text():$('.page>a:last').text();
let ImgList=[];
async function getImgUrl(array){
const ret = [];
const executing = [];
return new Promise(async (resolve, reject) => {
try {
for(let currentPage=0;currentPage<(+pageMax);currentPage++) {
let PageID = currentPage==0 ? `/${currentPageID}.html` : `/${currentPageID}_${currentPage}.html`,
PageUrl = location.pathname.replace(/\/[^/.]+\.html/i, PageID);
await $.get(PageUrl, (res,s,e)=>{
$('.content img', res).map(function(i, e){
ImgList.push(this.src);
//console.log(PageID, i, e, this.src)
});
})
}
} catch(e){
console.error(e);
} finally {
Promise.all(ret);
}
})
}
getImgUrl();
let padZero = (n) => (num) => {
if (typeof num === 'number') num += '';
return num.padStart(n, '0');
}
function requestUrlBlob(url) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
url: url,
method: 'get',
responseType : 'blob',
onload :res => resolve(res.response),
onerror : e => reject(e)
});
})
}
async function downloadAndPackFile(zipPack, url, filename, extname) {
if (!extname) {
const urlExt = url.split('.').pop();
extname = urlExt ? `.${urlExt}` : '';
}
console.log(`正在下载`, url, filename);
await requestUrlBlob(url).then((blob) => {
console.log(`下载完成`, url, blob, filename);
zipPack.file(`${filename}${extname}`, blob);
});
}
async function startDownload(ImgList, zipName) { // zipName = 压缩包名字
const zipPack = new window.JSZip();
const urlObjList = ImgList.map((url, idx) =>({url, filename: padZero(3)(idx),}));
console.log('开始下载');
await asyncPool(5, urlObjList, ({ url, filename }) => {
downloadAndPackFile(zipPack, url, filename);
});
await zipPack.generateAsync({ type: 'blob' }, function(metadata) {
let progress = metadata.percent / 100;
console.log(metadata, progress);
}).then(
function (blob) {
// 1) generate the zip file
window.saveAs(blob, `${zipName}.zip`); // 2) trigger the download
},
function (err) {
console.error('[批量下载] ERR', err);
}
);
console.log('资源下载完成,开始打包资源', zipName);
}
async function asyncPool(poolLimit, array, iteratorFn) { //通过任务池限制并发数量,任务池 poolLimit=任务上限,array=任务对象,iteratorFn=任务内容
const ret = [];
const executing = [];
for (const item of array) {
const task = Promise.resolve().then((y, n) => {
iteratorFn(item, array)
}); //等待处理完成
ret.push(task);
console.log(task);
if (poolLimit <= array.length) {
const e = task.then(() => executing.splice(executing.indexOf(e), 1));
executing.push(e);
if (executing.length >= poolLimit) {
await Promise.race(executing);
}
}
}
return Promise.all(ret);
}
对 Promise 不太熟悉,如上面的地址
startDownload 函数里
asyncPool 负责下载图片和打包
zipPack.generateAsync 执行下载动作
但是 zipPack.generateAsync没有等待 asyncPool 的 GM_xhr 完成就执行了下载动作,导致下载了一个空包
该怎么调整代码执行?
ThisAV 发表于 2022-1-24 15:59
感谢大佬回帖,是我的描述有问题,现有的代码就是这个操作方法
startDownload 函数里
感觉你对async/await的理解有问题,虽然强行异步后返回值变成了Promise,但代码实际还是同步的,这个downloadAndPackFile函数问题很大,return GM_xhr肯定得不到想要的结果,应该自己用Promise封装后return这个Promise(参考我给的download函数),asyncPool做的事跟我的downloadAll函数类似。 PS: 因为图片地址会进行 301 跳转,fetch 会受到 cors 影响 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
是想用promise.all函数么 看了一下,Gm_xhr不可以用await哦
他没有返回promise
可以自己封装一个
https://bbs.tampermonkey.net.cn/thread-883-1-1.html 给你写个简单示例:
function download(url) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
url: url,
method: 'get',
responseType : 'blob',
onload: res => resolve(res.response),
onerror: e => reject(e)
});
});
}
function downloadAll(urlList) {
const task = [];
for (let url of urlList) {
task.push(download(url));
}
return Promise.all(task);
}
要等待全部下载完成,await downloadAll()即可。 cxxjackie 发表于 2022-1-24 11:22
给你写个简单示例:
要等待全部下载完成,await downloadAll()即可。
大佬严谨!好久没看到cxxjackie哥哥了 李恒道 发表于 2022-1-24 10:50
看了一下,Gm_xhr不可以用await哦
他没有返回promise
可以自己封装一个
意思是我只能用递归的方法去满足我的需求? cxxjackie 发表于 2022-1-24 11:22
给你写个简单示例:
要等待全部下载完成,await downloadAll()即可。
感谢大佬回帖,是我的描述有问题,现有的代码就是这个操作方法
startDownload 函数里
asyncPool 负责下载图片和打包
zipPack.generateAsync 执行下载动作
但是 zipPack.generateAsync没有等待 asyncPool 的 GM_xhr 完成就执行了
该怎么优化这个? ThisAV 发表于 2022-1-24 14:58
意思是我只能用递归的方法去满足我的需求?
不用递归呀,
直接包装GM_xhr返回一个promise
然后全部塞到一个数组里
promise.all函数等待全部返回成功
进行下一步处理
页:
[1]
2