1

我确信“内在要求”不是正确的术语,但它很快就会在这里说得通。我正在研究工具包网站上的 Dijit 教程,我遇到了一个问题,我认为这更像是对 Javascript 的理解,而不是对 Dojo 的理解。

我的页面初始化脚本:

require(['player', 'dojo/dom', 'ready'], function(Player, dom){
    var p = new Player({
        type : 'video',
        dimensions : [720, 480]
    });
    p.setSource('videos/myvideo.webm')

    p.placeAt(dom.byId('stage') )
})

还有我的 dijit "player.js" 构造函数

constructor : function(opts){
    (function($){
        require(['sg/player/component/Video', 'sg/player/component/Audio'], function(Video, Audio){
            $._setMedia( (opts.type == 'video') ? new Video() : new Audio());
            console.log($._media) // outputs an object "a"
        })
    })(this);
    console.log(this._media) // also outputs the correct object, "a"
}

// the internal setter function used above
_setMedia : function(m){
    this._media = m;
},

(我有一个匿名函数的原因是我不喜欢var self = thisrequire块内分配,this不是包含对象。)

当我new Player()在 init 脚本中创建对象时,我可以看到其中一个Audio或的一个新实例Video被正确分配。但是,当我p.setSource()在初始化脚本中调用时,我得到一个_media空错误!

脚步

  • 创建播放器
    • 解析配置选项(类型、尺寸等)。内部_media对象持有Videoor的实例Audio
  • 允许在Player源之外访问setter方法!!错误 !!

所以我的问题,希望我提供了足够的上下文,但是为什么_media变量失去了它的价值?要从 Dijit 源外部访问的实例内部的任何方法Player都不应该对内部变量的范围产生任何影响,但这似乎是正在发生的事情。构造函数返回后,_media应该设置!但是使用

setSource : function(s){
    console.log('Setting source: ', s, this._media)
    // outputs ("Setting source: path/to/video.webm', null)
},

...引发错误,因为_media它在内部引用的变量setSource应该是空的。

希望这很清楚:)

更新

希望我能给你们两个复选标记!感谢您抽出宝贵时间提供帮助。

@Frode:肯定有一些异步问题迫使我学习并尝试更多的结构,所有这些都失败了,导致了这次更新。我认为在某些时候文件被缓存,导致变量内容不一致。

@phusick:我混合了您在下面发布的建议。

我考虑过重做 Player 实例化的结构、对象 arg 等,但决定执行以下操作,以防有人遇到这个问题......

我使用这种结构将AudioVideo类组合到_Media文件中(为简洁起见,删除了代码)

define(['dojo/_base/declare'], function(declare){
    var _base = declare("_Media", null, {        
        constructor : function(type){
            this._type = type;
        },
        // etc
    })
    return {
        Video : function(){
            return declare("Video", _base, {
                constructor : function(){
                    this.inherited(arguments, ['video'])
                }
                // etc
            })()
        },
        Audio : function(){
            return declare("Audio", _base, {
                constructor : function(){
                    this.inherited(arguments, ['audio'])
                }
                // etc
            })()
        },
    }
})

...这样一开始只加载一个文件,它包含两个子类。比在不使用一个文件时加载 2 个单独的文件要好,IMO。

对于播放器类型实例,它变为:

this._media = opts.type && opts.type == 'video' ? new Media.Video() : new Media.Audio();

到目前为止,一切都很好!再次感谢。

4

2 回答 2

1

构造函数返回后,应该设置_media!

我认为这是您采取错误步骤的地方。请记住,require 是一个异步函数!

但是,我对构造函数中的这一行(特别是注释)有点困惑:

console.log(this._media) // also outputs the correct object, "a"

您是否 100% 确定这会输出“a”而不是 null?如果是,请忽略我的其余答案,因为那我误解了一些东西:)

好的,如果您还在阅读,我将尝试解释异步需求。你打电话时:

require([".../Video",".../Audio"], function(Video, Audio) {
    // do something and set _media
});

你基本上是在说:“浏览器,你去后台为我获取视频和音频模块,而我继续我的下一行代码。当你获取它们后,运行我给你的设置_media的函数。”

换句话说,在 require() 完成并_media设置之前可能需要很长时间,但您的代码会立即继续。所以当你调用 setSource 时,require() 可能还没有完成(事实上,它甚至可能还没有开始下载任何东西)。

希望有帮助!

于 2012-06-18T22:03:52.307 回答
1

@Frode 是对的。实际上,即使异步操作足够快也行不通,因为 JavaScript 是单线程的,异步回调进入事件队列并通过事件循环一个接一个地执行。

另请参阅我对Dojo 1.7 如何在 require() 之外使用 dojo 组件的回答。

为什么您的player.js看起来不像这样有什么原因:

define([
    "sg/player/component/Video",
    "sg/player/component/Audio"
], function(
    Video,
    Audio
) {

    return declare([SomeSuperClass], {

        constructor: function(opts) {
            var media = opts.type && opts.type == "video" ? new Video() : new Audio();
            this._setMedia(media);
        }
    });

});
于 2012-06-19T01:20:37.107 回答