访问 Promise.then() 内的拖放对象?

时间:2021-03-14 04:49:16

标签: javascript html

问题

  • 我尝试访问 dataTransfer 对象。它在顶级代码中运行良好,但在 Promise.prototype.then() 中返回 undefined。

  • 拖放文件后,结果为LOG#1 = [object DataTransferItem] LOG#2 = undefined

  • 真实代码示例(从实际项目中简化):

    function dropHandler(e) {
    
        let fileNameList = [];
        let promise = new Promise((resolve, reject) => {
    
            console.log('File(s) dropped');
            e.preventDefault();
    
            if (e.dataTransfer.items) {
                    // Get list of all dropped file name.
                    for (var i = 0; i < e.dataTransfer.items.length; i++) {
                        if (e.dataTransfer.items[i].kind === 'file') {
                            fileNameList.push(e.dataTransfer.items[i].getAsFile().name);
                        }
                    }
    
                    // Read text from pairs.txt.
                    let pairsIndex = fileNameList.map(str => str.toLowerCase()).indexOf("pairs.txt");
                    let pairsFile = e.dataTransfer.items[pairsIndex].getAsFile();
                    console.log(pairsFile);
    
                    console.log("LOG#1 = " + e.dataTransfer.items[0]);
    
                    pairsFile.text().then(text => {
                        console.log("LOG#2 = " + e.dataTransfer.items[0]);
                        resolve();                  
                    });
            }
        });
    
        promise.finally(() => {
            e.dataTransfer.items.clear();
            fileNameList = [];
        });
    }
    
    function dragOverHandler(e) {
        console.log('File(s) in drop zone');
    
        // Prevent default behavior (Prevent file from being opened)
        e.preventDefault();
    }
    #drop_zone {
        border: 3px dashed;
        width:  100%;
        height: 300px;
      }
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>
    <body>
        <h5>Instruction: Drag and drop files to make quiz.</h5>
        <div id="drop_zone" ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
            <i class="bi bi-file-arrow-up" style="font-size: 10rem; color: rgb(189, 189, 189);"></i>
            <p>Drag one or more files to this Drop Zone ...</p>
        </div>
    </body>
    </html>

问题

  • 为什么 LOG#2 的结果未定义而 LOG#1 的结果正常?有什么方法可以访问它吗?

1 个答案:

答案 0 :(得分:1)

调用 .then() 后,您不再位于函数的原始调用堆栈中。这在事件侦听器中尤为重要。

我们可以用 setTimeout 重现同样的效果:

e.preventDefault();
  console.log(e.dataTransfer.items);
  setTimeout(()=> {
    console.log(e.dataTransfer.items);
  })

结果:

DataTransferItemList {0: DataTransferItem, 1: DataTransferItem, 2: DataTransferItem, 3: DataTransferItem, length: 4}  
DataTransferItemList {length: 0}

因此 DataTransfer 的上下文会随着时间而丢失。一种方法是在丢失之前复制所需的数据并在需要时重新使用它:

const items = [...e.dataTransfer.items];

function dropHandler(e) {

  let fileNameList = [];
  let promise = new Promise((resolve, reject) => {

    console.log('File(s) dropped');
    e.preventDefault();

    if (e.dataTransfer.items) {
      // Get list of all dropped file name.
      for (var i = 0; i < e.dataTransfer.items.length; i++) {
        if (e.dataTransfer.items[i].kind === 'file') {
          fileNameList.push(e.dataTransfer.items[i].getAsFile().name);
        }
      }

      // Read text from pairs.txt.
      let pairsIndex = fileNameList.map(str => str.toLowerCase()).indexOf("pairs.txt");
      // const items = [...e.dataTransfer.items];
      // const pairFiles = items[pairsIndex].getAsFile(); 
      // New code as per comment
      const items = [...e.dataTransfer.items].map(item => item.getAsFile());
      let pairsFile = items[pairsIndex];
      console.log(pairsFile);

      console.log("LOG#1 = " + items[0]);

      pairsFile.text().then(text => {
        console.log("LOG#2 = " + items[0]);
        resolve();
      });
    }
  });

  promise.finally(() => {
    e.dataTransfer.items.clear();
    fileNameList = [];
  });
}

function dragOverHandler(e) {
  console.log('File(s) in drop zone');

  // Prevent default behavior (Prevent file from being opened)
  e.preventDefault();
}
#drop_zone {
  border: 3px dashed;
  width: 100%;
  height: 300px;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <h5>Instruction: Drag and drop files to make quiz.</h5>
  <div id="drop_zone" ondrop="dropHandler(event);" ondragover="dragOverHandler(event);">
    <i class="bi bi-file-arrow-up" style="font-size: 10rem; color: rgb(189, 189, 189);"></i>
    <p>Drag one or more files to this Drop Zone ...</p>
  </div>
</body>

</html>

相关问题