等到诺言归还

时间:2019-06-20 00:01:20

标签: javascript html promise

我在Stackoverflow上找到了一些代码,可以从本地磁盘加载文件。一项大功能使一切正常。现在,我试图在较小的函数中将代码分开。

我想将DOM上的所有img.src加载到数组中,并将用户选择的文件添加到数组中。而不是对数组做些什么。

我创建了:

document.getElementById('picField').onchange = function (evt) {
    loadImg(evt);
}

async function loadImg(evt) {
    let imgInDom = await getImgFromDom();
    let allFiles = await loadAllFiles(imgInDom, evt);

    console.log(JSON.stringify(allFiles))
    //doSometing(allFiles);
    setTimeout(() => {
        console.log(JSON.stringify(allFiles))
    }, 2000);

}

function getImgFromDom() {
    return new Promise(resolve => {
        let elements = document.getElementsByClassName('loadedImg');
        let source = [];

        for (x = 0; x < elements.length; x++) {
            source.push(elements[x].src)
        }

        resolve(source);
    });
}

function loadAllFiles(imgFromDom, evt) {
    return new Promise(resolve => {
        let allFiles = [];

        let tgt = evt.target || window.event.srcElement,
            files = tgt.files;

        for (let x = 0; x < files.length; x++) {
            // FileReader support
            if (FileReader && files && files.length) {
                let fr = new FileReader();
                fr.readAsDataURL(files[x]);
                fr.onload = function () {
                    allFiles.push(fr.result);
                }
            }
            // Not supported
            else {
                // fallback -- perhaps submit the input to an iframe and temporarily store
                // them on the server until the user's session ends.
            }
        }

        resolve(allFiles);
    });
}
* {
    box-sizing: border-box;
}

body {
    margin: 0;
    font-family: Arial;
}

.row {
    display: flex;
    flex-wrap: wrap;
    padding: 0 4px;
    margin: 30px 60px;
    background-color: lightgray;
    border-style: ridge;
}

/* Create four equal columns that sits next to each other */
.column {
    flex: 25%;
    max-width: 25%;
    padding: 0 4px;
}

.img-overlay {
    position: relative;
    width: 100%;

}

.overlay {
    position: absolute;
    width: 32px;
    height: 32px;
    top: 6px;
    right: 3px;
    background-color: Transparent;
    background-repeat: no-repeat;
    border: none;
    cursor: pointer;
    overflow: hidden;
    outline: none;
}


.column img {
    margin-top: 4px;
    margin-bottom: 4px;
    vertical-align: middle;
    width: 100%;
}


/* Responsive layout - makes a two column-layout instead of four columns */
@media screen and (max-width: 800px) {
    .column {
        min-width: 50%;
    }
}

/* Responsive layout - makes the two columns stack on top of each other instead of next to each other */
@media screen and (max-width: 600px) {
    .column {
        min-width: 100%;
    }
}
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" type="text/css" href="style.css">
</head>

<body>
    <div id="load">
        <input type="file" name="picField" id="picField" size="24" onchange="preview_2(this);" alt="" accept="image/*"
            multiple />
    </div>
    <div class="row">
        <div class="column column1">
        </div>
        <div class="column column2">
        </div>
        <div class="column column3">
        </div>
        <div class="column column4">
        </div>
    </div>
</body>
<script src="/app.js"></script>

</html>

我希望代码会等到loadAllFiles()返回诺言。首先,我认为我的函数存在问题,因为在打印时allFiles是一个空数组。

但是当我将超时设置为2秒时,所有值都在数组中。

有人知道我在做什么错吗?

3 个答案:

答案 0 :(得分:1)

您要等待从 getImgFromDom()获取源。因此,我们将此函数用作Promise,并在then块中等待已解决的结果。当您收到数据时,我们要使用 loadAllFiles()加载文件。在这里,我们接收带有提供的源的文件,并以resolve返回文件,或者以reject返回错误。

function loadImg(evt) {
  this.getImgFromDom().then(imgInDom => {
    this.loadAllFiles(imgInDom, evt)
      .then(allFiles => {
        // console.log(allFiles) or return the files
      })
      .catch(error => {
        // reject error here
      });
  })


function getImgFromDom(): Promise<any> {
  return new Promise((resolve, reject) => {
    // logic here
    resolve(source);
  });
}


function loadAllFiles(imgFromDom, evt): Promise<any> {
  return new Promise((resolve, reject) => {
    // logic here
    resolve(allFiles);
    // error logic here
    reject();
  });
}

答案 1 :(得分:0)

我通过从fr.onload内解决问题来解决我的问题,就像建议的零298:

function loadAllFiles(imgFromDom, evt) {
    return new Promise(resolve => {

        let allFiles = [];
        allFiles = allFiles.concat(imgFromDom);

        let tgt = evt.target || window.event.srcElement,
            files = tgt.files;

        for (let x = 0; x < files.length; x++) {
            // FileReader support
            if (FileReader && files && files.length) {
                let fr = new FileReader();
                fr.readAsDataURL(files[x]);
                fr.onload = function () {
                    allFiles.push(fr.result);
                    if (x == files.length - 1) {
                        console.log(allFiles)
                        resolve(allFiles);
                    }

                }
            }
            // Not supported
            else {
                // fallback -- perhaps submit the input to an iframe and temporarily store
                // them on the server until the user's session ends.
            }
        }


    });
}

答案 2 :(得分:0)

因为您已经在使用诺言,所以我将它们链接起来。将您的loadImg方法替换为以下内容:

function loadImg(evt) {
    getImgFromDom().then(imgInDom => {
      return loadAllFiles(imgInDom, evt)
    }).then(allFiles => {
      console.log(JSON.stringify(allFiles))
    }).catch(error => {
      console.warn(error);
    });
}

将其与我未经测试编写的免责声明一起使用。 :)