使用库dom-to-image按顺序返回promise结果

时间:2018-02-22 11:34:02

标签: javascript promise

使用dom-to-image library我们可以使用Promises转换图像。

用法示例,从DOM对象转换为PNG图像:

var node = document.getElementById('my-node');

domtoimage.toPng(node)
    .then(function (dataUrl) {
        var img = new Image();
        img.src = dataUrl;
        document.body.appendChild(img);
    })
    .catch(function (error) {
        console.error('oops, something went wrong!', error);
    });

在幕后,toPng方法是Promise对象的链:

/**
 * @param {Node} node - The DOM Node object to render
 * @param {Object} options - Rendering options, @see {@link toSvg}
 * @return {Promise} - A promise that is fulfilled with a PNG image data URL
 * */
function toPng(node, options) {
    return draw(node, options || {})
        .then(function (canvas) {
            return canvas.toDataURL();
        });
}

我想基于Node数组转换图像,然后按顺序获取图像。问题是当我调用toPng()时,异步处理时间随DOM目标复杂度的变化而变化。因此它将在复杂性较低的页面之前返回,而不是按顺序返回页面。

let pages = document.querySelectorAll('.page');

pages.forEach(page => {
  let dataUrl = convertToPng(page.firstElementChild);
});

function convertToPng(page) {
  domtoimage.toPng(page)
    .then(function (dataUrl) {
      console.log(page); // prints pages randomly (e.g. page3, page1, page2) 
    })
}

一种可能的解决方案是使用Promise.all()方法并使用forEach()方法附加所有Promises。但在这种情况下,我使用的是外部库,我不知道如何获取第一页,然后是页面2,依此类推...

3 个答案:

答案 0 :(得分:3)

使用async / await

HTML:

<div class="page">Hello 1</div>
<div class="page">Hello 2</div>
<div class="page">Hello 3</div>
<div class="page">Hello 4</div>

JS(JSFiddle Link):

let pages = document.querySelectorAll('.page');

async function getPageUrls() {
    for (let page of pages) {
        const url = await convertToPng(page);
        console.log(url);
    }
}

async function convertToPng(page) {
    return await domtoimage.toPng(page);
}

getPageUrls();

基于OPs样本(JSFiddle):

let pages = document.querySelectorAll('.page');

for (let page of pages) {
    convertToPng(page);
}

async function convertToPng(page) {
    const dataUrl = await domtoimage.toPng(page);
    console.log(dataUrl);
}

getPageUrls();

使用此解决方案,代码执行将停止,直到convertToPng在每次迭代时产生结果。

答案 1 :(得分:2)

据我所知,您可以使用Promise.all。像这样的人:

let pages = document.querySelectorAll('.page');

Promise.all(Array.prototype.slice.call(pages,0)
.map(page =>domtoimage.toPng(page)
).then((pages)=>{.... your handler....});

有关Promise.all的更多信息,您可以从MDN

获取

答案 2 :(得分:2)

将promises链接起来以便顺序运行的最简单方法是使用Array#reduce

pages.reduce((promise, page) => 
    promise.then(() => convertToPng(page.firstElementChild)),
    Promise.resolve() // this starts the chain
);

正如您在评论wait until page1 is complete, before beginning with the next page

中所述,这将是

虽然,我觉得它只是输出顺序很重要,在这种情况下@VasylMoskalov的答案更合适

  

正如@Keith在评论中指出的那样 - convertToPng不会返回任何内容(更不用说承诺了)

function convertToPng(page) {
//vvvvvv important you return the promise here
  return domtoimage.toPng(page)
    .then(function (dataUrl) {
      console.log(page); // prints pages randomly (e.g. page3, page1, page2) 
    })
}