等待foreach里面的承诺

时间:2017-05-19 04:36:31

标签: javascript asynchronous promise jszip

我是承诺的新手。我知道一个是如何工作的。

我有一个函数将带有外部引用(图像,样式,脚本)的html文档转换为嵌入了这些资源的文件。它需要从异步源(JSZip实例)读取资源。

我希望函数只在所有promises zip.file().async().then(...)被解析后才返回。例如。有一个domDocument,然后对它执行一系列异步步骤,然后选择修改后的domDocument。可以修改调用此函数的区域以使用then(例如processFile(folder,zip,node,dom).then(function(result) ...如果需要。

// folder is set elsewhere
// zipObject is a JSZip instance
// node is an xml document which contains path references to files mentioned in the html
// domDocument is a DOMParser instance which is the html file

// these are the queryselectors for elements I want to match and replace in the html
[
    {"selector":"script[src]:not([src*='//'])","attribute":"src","type":"string"},
    {"selector":"link[href$='.css']:not([href*='//'])","attribute":"href","type":"string"},
    {"selector":"img:not([src*='//'])","attribute":"src","type":"base64"},
    {"selector":"a[target='_blank']:not([href*='://'])","type":"link"}
].forEach(function(element) {

    // grab all instances of a particular selector
    [].forEach.call(domDocument.querySelectorAll(element.selector), function(instance) {

        if (element.type === "link") { // replace link with plain text
            var tNode = document.createTextNode(instance.textContent);
            instance.parentNode.replaceChild(tNode, instance);

        } else { // need to load from the linked document
            var value = unescape(instance.getAttribute(element.attribute)),
                    path = null;

                // images that are already encoded can be ignored
                if (element.type==="base64" && (-1!==value.indexOf("data:image"))) return;

            if (value.indexOf("../")==0) { // resolve dependancy filename
                var dep = node.parentNode.querySelector("dependency");
                if (null !== dep) {
                    var ref = node.parentNode.parentNode.querySelector("resource[identifier='" + dep.getAttribute("identifierref") + "']");
                    if (null !== ref) {
                        path = ref.querySelector("file[href]").getAttribute("href");
                    }
                }
            } else { // resolve path from filename
                path = folder + value;
            }

            // perform the (asynchronous) modification of the document
            zipObject.file(path).async(element.type).then(function success(content) {
                if (element.attribute === "href") {
                    // <link href="file.css"> ==> <style>(file contents)</style>
                    var style = document.createElement("style");
                    style.appendChild(document.createTextNode(content));
                    instance.parentNode.replaceChild(style,instance);
                } else if (element.type === "base64") {
                    // <img src="file.gif"> ==> <img src="data:image/gif;base64,(image-contents)">
                    var extn = value.substr(value.lastIndexOf(".") + 1).toLowerCase();
                    instance.setAttribute("src", "data:image/" + extn + ";base64," + content);
                } else {
                    // <sript src="file.js"></script> => <script>(file-contents</script>)
                    instance.removeAttribute(element.attribute);
                    instance.appendChild(document.createTextNode(content));
                }
            }, function error (e) {
                console.log("ConvertZipForHtml Error", e);
                // leave it alone I guess
            });
        }
    });
});

// want this to return the MODIFIED version of the string
return domDocument;

我可以看到第一个数组的每次迭代都需要是一个promise,并且整个函数只应在所有这些promises解析后返回,但我无法弄清楚如何

/编辑:

我想我明白了(感谢@Bergi)。如果我做了一个承诺,它返回了每个只在JSZip的异步函数解析之后解析的项的承诺,那么它似乎异步工作,我的外部函数可以在所有promise完成后使用.then()。

function myFunction(args) {
    function replaceElements(elements) {
        return Promise.all(elements.map(selectElements));
    }

    function selectElements(element) {
        return new Promise(function (resolve, reject) {
            var myNodeList = domDocument.querySelectorAll(element.selector);
            for (var i = myNodeList.length; i--;) { // (generally is faster than forwards!)
                var instance = myNodeList[i];
                // -- snip --
                zipObject.file(path).async(element.type).then(function success(content) {
                    // -- snip --
                    resolve(instance);
                })
            }
        });
    }

    return replaceElements([
        {"selector":"script[src]:not([src*='//'])", "attribute":"src", "type":"string"},
        {"selector":"link[href$='.css']:not([href*='//'])", "attribute":"href", "type":"string"},
        {"selector":"img:not([src*='//'])", "attribute":"src", "type":"base64"},
        {"selector":"a[target='_blank']:not([href*='://'])", "type":"link"}
    ]);
}

仍然抓住异步和承诺中的概念

0 个答案:

没有答案