【问题标题】:Declaring class differently for different Dojo versions without duplicating code?在不重复代码的情况下为不同的 Dojo 版本声明不同的类?
【发布时间】:2014-08-24 04:29:37
【问题描述】:

我有一个为 IBM Connections 设计的 iWidget,我的 javascript 代码依赖于 Dojo(默认情况下包含在 Connections 中)。
它目前在 Connections 4.0 和 4.5 中工作,但在 Connections 5.0(上周发布)中被破坏,因为 Dojo 已更新到 v1.9 并抱怨我使用 dojo.require

当我的小部件尝试在 Connections 5.0 上加载时,这些消息会出现在浏览器控制台中:

避免在运行时调用 dojo.require() 来加载类,改用 net.jazz.ajax.xdloader.load_async()。函数“(匿名)”需要类“dojox.atom.io.model”。
避免在运行时调用 dojo.require() 来加载类,请改用 net.jazz.ajax.xdloader.load_async()。函数“(匿名)”需要类“dojox.atom.io.Connection”。

我想制作条件代码,使用不同的方式定义我的小部件类并根据 Dojo 版本需要其他 Dojo 模块。

小部件 javascript 当前如下所示:

dojo.provide('insightCommunityWidgetClass');
dojo.require('dojox.atom.io.model');
dojo.require('dojox.atom.io.Connection');

dojo.declare('insightCommunityWidgetClass',null,{
    // Class fields and methods. Currently 680 lines uncompressed.
});

我还没有创建适用于 Dojo 1.9 / Connections 5.0 的版本,但我认为它看起来像这样(我必须使我的 javascript 文件名与所需的类名匹配):

define(['dojo/_base/declare','dojox.atom.io.model','dojox.atom.io.Connection'], function(declare){
    return declare(null, {
        // Class fields and methods.
    });
});

我怎样才能将这两者放在一个文件中并在它们之间进行选择而不复制类主体?

更新:
我尝试了一些条件代码,按照 Dimitri 的建议检查了(define && define.amd),在 Connections 4.0 和 4.5 上对此进行了测试,并且出现了非常奇怪的行为。

暂时忽略任何不复制我的类的尝试,这里有一些条件代码,我使用的完全如图所示,小部件类严重减少:

if (define && define.amd) {
    console.log('Declaring insightWidgetClass with AMD (new method).');
    define(['dojo/_base/declare','dojox/atom/io/model','dojox/atom/io/Connection'],
        function(declare){
            return declare(null,{
                SVC_INV: 1,
                onLoad: function() {
                    console.log('insightWidgetClass onLoad.');
                }
            });
        }
    );

} else {
    console.log('Declaring insightWidgetClass with dojo.declare (old method).');
    dojo.provide('insightWidgetClass');
    dojo.require('dojox.atom.io.model');
    dojo.require('dojox.atom.io.Connection');

    dojo.declare('insightWidgetClass',null,{
        SVC_INV: 1,
        onLoad: function() {
            console.log('insightWidgetClass onLoad.');
        }
    });
}

这似乎根本没有运行。我的console.log 消息都没有出现在浏览器控制台中。

如果我注释掉条件并使其唯一的活动代码是else 之后的块,它就会运行。我收到“声明...(旧方法)”和“insightWidgetClass onLoad”控制台消息。

我认为可能将 Dojo providerequiredeclare 调用包含在任何类型的块中可能会导致问题,所以我测试只是将工作代码放在 if (true) { 块中,它仍然有效.

此时我尝试的最后一件事是在其他所有内容之前添加这一行,看看define 是什么:

console.log('dojo define',define);

... 这打破了它。我的代码中根本没有控制台消息。
然后我从该新行中删除 define 参数,因此它只是向控制台发送一个字符串,并且代码再次工作。
似乎任何提及 define 标识符都会默默地阻止其余代码运行。
控制台中没有指示问题的错误或警告。我只能说:WTF?!

现在返回检查dojo.version

【问题讨论】:

  • 只是一个建议。您可以尝试使用 dojo.version 将特定于 dojo 版本的代码包含在内,有关详细信息,请参阅 here
  • @frank - 我知道 dojo.version 对象,但我无法从该文档中看到当只有 dojo.providedojo.requiredojo.declare 行需要针对不同的 Dojo 版本进行更改。
  • 还有一个已知的模块有dojo.has。有关详细信息,请参阅here,这可能对您的方案有用。 dojo.has 可以按照 this 教程用于创建特定构建。希望这会有所帮助

标签: javascript dojo ibm-connections


【解决方案1】:

通常两者都应该仍然有效,dojo.provide()dojo.require() 已被弃用,但并未完全删除。只需确保您的加载道场处于同步模式即可。

除此之外,Dojo 1.7 中引入了 AMD 编码方式,这意味着它也应该在 IBM Connections 4.5 上得到支持(虽然我不知道 IBM Connections 4)。

但如果你真的想同时使用这两个代码库,你可以简单地引用同一个对象而不是复制它,例如:

var myModule = {
    // Class fields and methods.
};
if (dojo.version.major == 1 && dojo.version.minor == 9) {
    define(['dojo/_base/declare','dojox.atom.io.model','dojox.atom.io.Connection'], function(declare){
        return declare(null, myModule);
    });
} else {
    dojo.provide('insightCommunityWidgetClass');
    dojo.require('dojox.atom.io.model');
    dojo.require('dojox.atom.io.Connection');

    dojo.declare('insightCommunityWidgetClass',null, myModule);  
}

或者您可以使用以下检查:

if (typeof define === 'function' && define.amd) {
    // AMD style code
} else {
    // Non-AMD style code
}

这是大多数跨加载器库使用的方法。既可以在 AMD 加载器(Dojo、Require.js)上运行,也可以在 Node.js 上运行或仅通过使用全局命名空间的库使用类似的代码来确定它们如何加载其模块。

【讨论】:

  • 我确实尝试过这样做。小部件框架似乎有问题。没有错误,但是当我以这种方式编写它时,小部件的 onLoad 方法永远不会运行。我将尝试使用原型方法将类定义为函数,例如phpied.com/3-ways-to-define-a-javascript-class 的第 1.2 点。
  • 还注意到检查define && define.amd 似乎是一个好建议;比检查版本号更好。
  • @ScottLeis 确实,我认为这是检查这些事情的首选方式。许多库都这样做,例如看看 Moment.js,它做了类似的检查:github.com/moment/moment/blob/develop/moment.js#L2723
  • 我更新了我的问题,详细介绍了我试图检查define 的一个奇怪问题。我再次尝试设置类变量(如您的回答),现在似乎可以在 Connections 4.0 和 4.5 中使用,所以当该解决方案最初失败时,我一定犯了一些错误。目前我们的 Connections 5.0 (Dojo 1.9) 环境存在更大的问题,因此可能需要几天时间才能确认答案。
  • 在旧代码中使用dojo.require(),在AMD 中require()define() 之间存在差异。 define() 仅在稍后在 require() 函数中导入模块时才有效。所以define() 仅适用于定义模块,但要使用该模块,您必须require() 它。
【解决方案2】:

这不是您的代码,它应该可以正常工作。我们最近遇到了同样的问题并确定了原因。

Connections 5 使用 AMD 版本的 Jazz 框架,它提供了自己的 dojo 加载器。该框架用于将所需的 dojo 模块聚合到单个 JS 文件中,从而限制了对服务器的请求数量。不幸的是,这个加载器不再处理同步模块加载。当 dojo.require() 请求聚合器尚未加载的模块时,它会失败并显示您报告的警告。如果模块已经加载,因为它是 Jazz 聚合文件的一部分,那么它可以工作。它解释了为什么你可以 dojo.require() 一些模块,但不是全部。

-> 一种解决方法是部署一个服务器端 OSGi 包,以获取您需要的模块作为聚合 JS 文件的一部分。有一个文档化的扩展点。这可以解除对您的阻碍,同时提高页面的性能。

现在,我们向 IBM 支持人员开放了 PMR。开发团队正在制定解决方案。我们希望他们能够尽快提供修复。

我们报告了以下问题:

  • dojo.require()
  • dojo.requireLocalization()
  • dojo.registerModulePath()/require({paths:})

如果您有其他想法,请告诉我。

【讨论】:

  • 谢谢,菲利普。这很有趣。我会密切关注与此相关的任何 Connections 修复。
  • 据我了解,这应该在 C5 CR1 中修复,如果您更早需要,还可以使用 iFix。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-21
相关资源
最近更新 更多