我有一个名为urlExists的函数,该函数在多个项目中使用都没有问题。现在我在患者面板中,需要在调用函数addEventListener之前检查是否存在js文件:
function urlExists(url){
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.onreadystatechange = function(){
if(request.readyState==4){
return true;
}else{
return false;
}
}
}
//other part of code
if (urlExists('../../medvoice/speaker.js')){
beep.addEventListener('ended', function() {
var parameters = {
target: dados,
tts: {
name: 'lianetts'
},
binder: 'speak',
path: {
name: '../../medvoice/mediapool/',
link: '/medhosphsl/medvoice/mediapool/'
}
};
var speaker = new Speaker(parameters);
});
}
当在urlExists内放一个控制台日志时,控制台会显示测试短语,但在onreadystatechange里面却不会。我丢失了什么?
最佳答案
有几个问题:
您的return true
和return false
不是从urlExists
返回的,而是从onreadystatechange
回调返回的。 urlExists
在任何地方都没有显式的return
,因此调用它总是导致undefined
。
您永远不会调用send
来触发请求。
您正在使用readyState
来确定资源是否存在,但这只是告诉您请求的状态。您应该检查status
。
如果必须使用同步请求,则完全不需要或不需要onreadystatechange
处理程序。这是解决所有这些问题的版本:
function urlExists(url){
var http = new XMLHttpRequest();
http.open('HEAD', url, false);
http.send();
return http.status === 200;
}
出于完整性考虑:同步ajax请求使UX效果不佳,并且可能在某个时候完全淘汰。相反,请使用异步请求并让
urlExists
返回promise:function urlExists(url){
return new Promise(function(resolve) {
var http = new XMLHttpRequest();
http.open('HEAD', url);
http.onreadystatechange = function() {
if (http.readyState === 4) {
resolve(http.status === 200);
}
};
http.send();
});
}
// Usage:
urlExists("some-url").then(function(exists) {
console.log("Exists? " + exists);
});
或使用
fetch
和ES2015 +箭头功能的更现代的方式:function urlExists(url) {
return fetch(url, {method: "HEAD"}).then(response => response.ok);
}
// Usage:
urlExists("some-url").then(exists => console.log("Exists? " + exists));
或者我们可以拥抱ES2017(下个月发布!):
async function urlExists(url) {
return (await fetch(url, {method: "HEAD"})).ok;
}
// Usage (in another async function):
console.log("Exists? " + await urlExists("some-url"));
旁注:
urlExists
仅适用于您可以通过ajax访问的URL,因此通常仅源于同一来源的URL。如果那是您的用例,那很好,但是我想我会提到它。