为何将$(document).ready()包裹在Promise中会触发TypeError错误?
你遇到的这个错误其实是个典型的API返回值混淆问题,核心原因一句话就能说清:jQuery的$(document).ready()方法返回的是jQuery对象,不是Promise,所以它根本没有.then()方法可以调用!
咱们拆解来看:
1. 单独使用$(document).ready()为啥正常?
当你单独写$(document).ready(function(){...})时,你只是把一个回调函数传给了ready方法——jQuery会在DOM就绪时自动执行这个回调,这时候你并没有去调用什么.then()方法,自然不会触发错误。
2. 你的代码哪里出问题了?
看你代码里的这条链:
$(document).ready(function () { arr.push(1); res(arr); }).then((response) => { console.log(response); });
这里你误以为$(document).ready()会返回一个Promise,所以直接在后面链式调用了.then()。但实际上,jQuery的ready方法返回的是jQuery包装后的document对象(也就是$(document)),这个对象上只有jQuery的API(比如.find()、.css()这些),完全没有Promise的.then()、.catch()方法,浏览器自然会抛出TypeError: $(...).ready(...).then is not a function的错误。
3. 正确的写法应该是怎样的?
你需要把.then()绑定到Promise实例上,而不是ready()的返回值上。调整后的代码可以是这样:
function solution() { let pro = new Promise((res, rej) => { // 在这里用ready触发Promise的resolve $(document).ready(function () { let arr = []; arr.push(1); res(arr); }); }); // 给Promise实例添加then回调,而不是给ready的返回值加 pro.then((response) => { console.log(response); }); } solution();
或者更简洁地封装一个DOM就绪的Promise工具函数:
// 封装成可复用的Promise版DOM就绪方法 function waitForDomReady() { return new Promise(resolve => { $(document).ready(resolve); }); } function solution() { waitForDomReady().then(() => { let arr = [1]; console.log(arr); }); } solution();
额外补充:jQuery 3.0+的小细节
如果你用的是jQuery 3.0及以上版本,它的Deferred对象已经和原生Promise兼容了,但ready()方法依然不会返回Promise——它还是返回jQuery对象。如果想更贴近原生Promise的写法,也可以直接用原生DOM事件来封装:
function waitForDomReady() { return new Promise(resolve => { if (document.readyState === "complete" || document.readyState === "interactive") { resolve(); } else { document.addEventListener("DOMContentLoaded", resolve); } }); }
内容的提问来源于stack exchange,提问作者assiegee

