有没有办法在外部包不可用时优雅地失败,并且仍然运行 domReady
Is there a way to gracefully fail when an external package is not available and still run domReady?
我正在 Dojo 1.7.2 中创建一个共享栏小部件,并使用require()
有条件地将外部社交媒体 API 加载为包,如下所示:
require({
packages:[
{name: "twitter-api", location: "https://platform.twitter.com", main: "widgets"}
]
},["twitter-api"], lang.hitch(this, function(){
// Do some social stuff with twitter API
}));
每当我可以访问 Twitter API 时,这都很好用,但现在我正在通过专用网络对其进行测试,我不能。 问题不在于小部件不起作用。 相反,我有一些额外的代码从ready()
内运行,对于domReady()
也是如此,在尝试加载包并且加载失败后调用。
我对 Dojo 文档进行了一些挖掘,以找出为什么我的 ready 没有触发并遇到了这个推理(domReady):
现在来了 dojo/domReady!.加载器加载所有依赖项 对于道场/多姆准备!然后要求解决插件资源。 但是道场/多姆准备好了!可能无法解决所需的插件 资源(一个空的模块 ID,旨在指示 DOM 是 ready),因为 DOM 可能还没有准备好。加载程序注意到这一点 看到模块无法同步加载, 放弃并继续。
这是加载器中的有意限制,因为处理它 将需要更复杂的代码。它将不再是 Dojo 2.0 的问题,当同步加载程序不受支持时。
从我收集的信息来看,Dojo 会在无法加载依赖项时停止尝试。 这很好,但是有没有办法优雅地处理外部库不可用的情况?
我想也许有一些方法可以通过 XHR 调用来做到这一点,但这会导致跨源问题。 我唯一的其他解决方案是将它们添加为单独的脚本标签,这就是加载其他一些库的方式;但由于这个模块现在正在重构,我想尝试让它尽可能兼容 AMD。
您可以创建一个承诺并在请求成功时解决它; 并在 promise 的错误处理程序中优雅地失败:
require(["dojo/Deferred"], function(Deferred){
var d = new Deferred();
require(['twitter-api'], function(twitterApi){
d.resolve(twitterApi);
});
d.then(function(api){
// use api
}, function(err){
// fail gracefully
});
return d.promise;
});
Stafamus的回答是解决手头问题的一个非常接近的解决方案。 实际上,由于您无法确定require
是否会完成,因此您不能尝试解决或拒绝其中的承诺。 我最终将dojo/Deferred
与dojo.io.script
结合使用,以便异步加载 Twitter API,然后在加载 Twitter API 时调用的回调中解析承诺。
还要记住,我使用的是 Dojo 1.7.2。 从 Dojo 1.8 开始,dojo.io.script
被弃用,取而代之的是 dojo/request/script
。 我没有研究两者之间的区别。
这段代码可能会优化得更好一点,例如,我认为你不需要使用declare
或者如果你这样做,你可以创建一个基 API 类,我不确定如果你尝试在页面上多次使用或加载 Twitter API,它是否运行得非常好。 但是,它符合我的需求,我已经调整了此解决方案,以类似的方式加载Youtube,Google和Facebook API。
推特.js
基本上,代码归结为使用dojo.io.script
让Dojo在页面上放置带有Twitter src的<script>
标签,这使我们获得了Twitter使用的全局,twttr
并试图确保它不需要的话不会这样做。 Twitter 有一个"就绪"回调,通过t.ready()
定义,我们通过引用全局twttr
来解决我们的 API 承诺。 实际上,这是Twitter告诉你的Dojo包装方式,已经加载JavaScript API。
define([
"dojo/_base/declare",
"dojo/_base/Deferred",
"dojo/io/script"
], function (
declare,
Deferred,
ioScript
) {
/**
* @class api/Twitter
* @classdesc Wrapper for the Twitter API which isn't inherently AMD
*/
var Twitter = declare("api.Twitter", [], {
/**
* The deferred that we use to get a handle to API
* @member {dojo/Deferred} api/Twitter#apiDeferred
*/
apiDeferred: null,
/**
* The constructor which loads the API and starts the player creation
* @method api/Twitter#constructor
* @param {HTMLElement} container The id of the element to hold the player
*/
constructor: function (container) {
// Create a deferred that will resolve when we have a player
this.apiDeferred = this.loadAPI();
},
/**
* Function that loads the API from Twitter asynchronously
* @method api/Twitter#loadAPI
* @return {dojo/Deferred} The deferred that will resolve when the API is loaded
*/
loadAPI: function () {
// Create an API deferred to resolve when the API is loaded
var apiDeferred = new Deferred();
// Make sure that we haven't already loaded the Twitter API
if (typeof twttr === "undefined") {
/*
* This is where we wrap up the normally "synchronous" loading
* of whatever API we're using. Twitter is slightly asynchronous
* in that it loads itself through creating a script tag and setting
* the src which we can do with dojo.io.script already. However,
* twitter expects there to exist a "twttr" variable whenever it loads
* much like dojo expects a dojoConfig. In the twttr, there is an array
* of callbacks _e that will be called once the API is loaded. This is
* where we create the boilerplate for Twitter.
*/
// Create the twttr object from an immediately executed functor
window.twttr = (function () {
// Make sure we don't already have a twttr object
var t = window.twttr || {};
// Create a ready callback array
t._e = [];
// Create a wrapper to allow pushing to the ready array
t.ready = function (f) {
t._e.push(f);
};
// Add our on callback that will let us know twitter loaded
t.ready(function (e) {
// Deliver the API through the deferred
apiDeferred.resolve(e.widgets);
});
// Return the twitter object
return t;
}());
// Ask dojo to load a new script tag with the Twitter API as the src
ioScript.get({
url: "https://platform.twitter.com/widgets.js",
error: function (e) {
apiDeferred.reject("Twitter API seems incorrectly loaded.");
}
});
}
// If we already have the Twitter API, we can resolve right now
else {
if (typeof twttr.widgets !== "undefined") {
apiDeferred.resolve(twttr.widgets);
}
else {
apiDeferred.reject("Twitter API seems incorrectly loaded.");
}
}
// Return the API Deferred
return apiDeferred;
},
/**
* Function to get a handle to the deferred that should resolve to the twitter API
* @member api/Twitter#getAPIDeferred
* @returns {dojo/Deferred} The Twitter API
*/
getAPIDeferred: function () {
return this.apiDeferred;
}
});
// Return our class
return Twitter;
});
共享吧.js
在我的小部件中,我有开关让我禁用社交 API,如果我想使用一个,我只需要上面的包装 API。 然后我创建一个新Twitter
,请求 API 延迟,如果它解析,我创建 Twitter 按钮。 此文件被严重截断,不包括所有小部件代码,仅包含 API 代码的实际使用。
define([
"dojo/_base/declare",
"Twitter"
], function (
declare,
Twitter
) {
/**
* @class ShareBar
* @classdesc Widget used to display social media functionality on a page.
*/
var ShareBar = declare({
/**
* By requiring the Twitter API, we have the twttr JS
* object which we can use to do Twitter stuff like
* parsing tweet buttons
* @method ShareBar#_loadTwitter
*/
_loadTwitter: function () {
var
// Create a twitter module
twitter = new Twitter(),
// Get a closure safe handle to our twitter button
twitterButton = this.TwitterButton,
// Create a callback for when the twitter API loads
twitterSuccess = function (twitterAPI) {
// Run the twitter parser on our twitter button
twitterAPI.load(twitterButton);
// Allow the twitter button to be seen
domClass.remove(twitterButton, "hiddenSocialButton");
},
// Create an errback for if the twitter API fails
twitterFail = function (err) {
// Note the error
console.log(err);
};
// Wait for the API to resolve and use the callbacks
twitter.getAPIDeferred().then(twitterSuccess, twitterFail);
}
});
// Return widget
return ShareBar;
});
- 当json解析空响应时,Whatwg-Fetch失败,我该如何防止它
- JsFiddle在分叉后描述失败
- 为什么不'当单元测试出现解析错误时,我的因果报应测试会失败
- 当一些承诺失败时,如何继续使用$q.all()
- 失败:等待Protractor与页面同步时出错:“”;在窗口上找不到角度”;
- 在Jquery中单击传播失败
- 网页上失败的javascript会导致所有其他脚本失败
- 带有对象解析的响应javascript ajax失败
- 一台特定计算机的Ajax请求数据未定义/失败
- Nodejs服务器:加载资源失败:服务器的响应状态为404(未找到)
- jQuery.getJSON失败,语法错误
- ng disabled在放入多个表达式时失败
- Jasmine单元测试在监视服务方法时失败
- jQuery分页下一页和上一页按钮在点击零或超过最后一页后失败
- 在iframe的情况下,jQuery html()将失败
- 在我的情况下,使用带有变量失败的 jquery 选择器
- CSS中的转换似乎失败了,原因是什么
- 在数组中插入对象失败
- Backbone fetch中的Ajax在fetch调用退出后完成,因此fetch调用中没有成功/失败事件
- 有没有办法在外部包不可用时优雅地失败,并且仍然运行 domReady