javascript - Return a promise result in order using the library dom-to-image - Stack Overflow

admin2025-04-10  0

Using the dom-to-image library we can convert an image using Promises.

Usage example, conversion from DOM object to PNG image:

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);
    });

Behind the scenes, the toPng method is chain of a Promise object:

/**
 * @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();
        });
}

I want to convert images based on a Node array, and then, to get that images in order. The problem is when I call toPng() the async process time varies in function of the DOM target plexity. So it will return before the pages with less plexity, instead of return the pages in order.

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) 
    })
}

A possible solution would be use a Promise.all() method and attach with a forEach() method all the Promises. But in this case, that I'm using an external library, I don't know how to approach in order to get first the page1, then the page 2, and so on...

Using the dom-to-image library we can convert an image using Promises.

Usage example, conversion from DOM object to PNG image:

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);
    });

Behind the scenes, the toPng method is chain of a Promise object:

/**
 * @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();
        });
}

I want to convert images based on a Node array, and then, to get that images in order. The problem is when I call toPng() the async process time varies in function of the DOM target plexity. So it will return before the pages with less plexity, instead of return the pages in order.

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) 
    })
}

A possible solution would be use a Promise.all() method and attach with a forEach() method all the Promises. But in this case, that I'm using an external library, I don't know how to approach in order to get first the page1, then the page 2, and so on...

Share Improve this question edited Apr 22, 2018 at 5:47 Stephen Docy 4,7887 gold badges21 silver badges31 bronze badges asked Feb 22, 2018 at 11:34 Angel LuisAngel Luis 3224 silver badges14 bronze badges 6
  • chain the promises perhaps? I assume you want to wait until page1 is "plete" before beginning on page2 etc? – Jaromanda X Commented Feb 22, 2018 at 11:35
  • @JaromandaX yes I want to wait until page1 is plete, before beginning with the next page. – Angel Luis Commented Feb 22, 2018 at 11:37
  • If you want to be really hip, try using async / await – Keith Commented Feb 22, 2018 at 11:37
  • @Keith I know async / await but I don't know how to apply it in this library. – Angel Luis Commented Feb 22, 2018 at 11:41
  • 1 ps.. Also make sure you return your promise from convertToPng... – Keith Commented Feb 22, 2018 at 11:48
 |  Show 1 more ment

3 Answers 3

Reset to default 3

As I understand for this case you can use Promise.all. Smthing like this one:

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

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

More information about Promise.all you can get from MDN

Using 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();

Based off OPs sample (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();

With this solution code execution is stopped until convertToPng yields a result at each iteration.

The easiest way to chain the promises so they run in sequence is using Array#reduce

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

This will, as you stated in the ment wait until page1 is plete, before beginning with the next page

Though, I get the feeling it's only the output order that is important, in which case the answer by @VasylMoskalov is more appropriate

As @Keith pointed out in a ment - convertToPng does not return anything (let alone a promise)

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) 
    })
}
转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1744257929a238405.html

最新回复(0)