为什么JavaScript代码执行顺序颠倒,Line 2先于Line 1执行?
执行顺序颠倒的核心原因
这是JavaScript异步IO的执行机制导致的,FileReader提供的readAsBinaryString是异步文件读取接口,不会阻塞JavaScript主线程的后续代码执行,你传入的回调函数只会在文件读取完成后才会被触发执行。
实际代码执行顺序
- 第一步:先声明
fileToSend变量,初始值为undefined - 第二步:调用
base64函数,内部完成文件基础属性读取、给reader.onload绑定回调后,执行reader.readAsBinaryString(file),此时浏览器会在后台线程启动文件读取任务,主线程不会等待读取完成,直接继续向下执行 - 第三步:主线程立刻执行
console.log('\n Line 2 \t' + fileToSend),此时文件还没读取完成,fileToSend还没被赋值,所以输出undefined - 第四步:后台线程完成文件读取后,才会触发
reader.onload事件,执行你传入的回调函数,此时才会给fileToSend赋值并打印Line 1的日志,因此你会看到Line2的输出早于Line1。
解决方案
方案1:回调内处理依赖逻辑
所有需要用到fileToSend的逻辑,直接放在回调函数内部执行即可:
base64($('input[type="file"]'), function (filedata) { var convertedFile = filedata.base64; console.log('\n file SB1 \t' + convertedFile); const fileToSend = convertedFile; console.log ('Line 1 \t' + fileToSend); // 所有用到fileToSend的逻辑都写在这里,比如提交接口、数据处理等 uploadFile(fileToSend) });
方案2:封装为Promise使用async/await语法
如果不想嵌套回调,可以把base64函数改造为返回Promise的形式,用更扁平的async/await写法:
// 改造base64函数 function base64(file) { return new Promise((resolve, reject) => { var coolFile = {}; var reader = new FileReader(); reader.onload = function(e) { var base64 = btoa(e.target.result); coolFile.base64 = base64; resolve(coolFile); } reader.onerror = function(err) { reject(err) } var targetFile = file[0].files[0]; coolFile.filetype = targetFile.type; coolFile.size = targetFile.size; coolFile.filename = targetFile.name; reader.readAsBinaryString(targetFile); }) } // 调用示例 async function processFile() { const filedata = await base64($('input[type="file"]')) const fileToSend = filedata.base64 console.log ('Line 1 \t' + fileToSend); console.log('\n Line 2 \t' + fileToSend); // 后续逻辑 } processFile()
内容的提问来源于stack exchange,提问作者Hello Universe
相关产品推荐
相关产品推荐

