<Page>

    <h1>事件触发</h1>
    <h2>基本用法</h2>

    <p>Roof 的事件触发简单易懂。不过注意养成给监听函数取名字的好习惯。</p>
    <Code type='javascript'>{`
    var Bus = require("roof-bus")
var bus = new Bus

//设置监听器,记得函数最好命名
bus.on("dance", function soWeDance( arg1, arg2 ){})

//触发事件,参数可以任意多个，会依次传给监听器
bus.fire("dance", arg1, arg2 )
.then(function resolved(){}, function rejected(){})

    `}</Code>

    <h2>
        异步等待
    </h2>

    <p>无论监听器内的操作是否是异步。`bus.fire`方法都会返回一个promise。如果监听器内有异步操作，默认情况下，bus是不会管监听器的异步操作是否执行完了的。如果我们需要 bus.fire 返回的 promise 在监听器的异步操作执行完侯再 resolve， 那么我们需要显式地在监听器里返回一个promise。例如：</p>

    <Code  type='javascript'>{`
    var danced = false
bus.on("dance", function weDance(){
    //返回promise，告诉bus等我完成再resolve
    return new Promise(function(resolve, reject){
        window.setTimeout(function(){
            danced = true
            resolve()
        },1000)
    })
})


bus.fire("dance").then(function(){
    //weDance完成后这里才执行
    console.log(danced === true) //true
})
    `}</Code>

    <h2>级联触发</h2>

    <p>有时我们在一个监听器内部会再触发新的事件，这里有一点需要注意，就是必须用当前监听器的this指针来触发。只有这样才能保证最后事件的调用栈是正确。详情请咨询Roof开发小组。</p>

    <Code type='javascript'>{`
    bus.on("dance", function weDance(){

    //注意！这里必须使用监听器内部的this指针来触发新的事件
    return this.fire("sing").then(function(){})
})
    `}</Code>

    <h1>数据传递</h1>

    <p>事件触发过程中的需要传递数据的情况分为两种：</p>

    <ul>
        <li>监听同一事件的监听器之间互相传递数据</li>
        <li>监听器和外部的数据传递</li>
    </ul>

    <h2>同一事件的监听器间传递数据</h2>

    <p>下面的例子演示如何传递数据</p>

    <Code type='javascript'>{`
    bus.on("dance", function jhonDance(){
    this.data.set("jhonDanced",true)
})

bus.on("dance", {
    fn : function mayaDance(){
        if( this.data.get("jhonDanced") ){
            console.log("great!")
        }
    },
    after :"jhonDance"
})
    `}</Code>

    <p>通常数据间有依赖的监听器，也会有顺序的依赖，上面的例子演示的就是第二个监听器依赖第一个监听器数据情况。这里注意，使用 `this.data.set` 存储的数据只在同级间传递，不会传递到触发的子事件中。需要穿透的话请看下一节。</p>

    <h2>监听器与外界的数据传递</h2>

    <h3>通过 global 传递</h3>

    <p>使用方法跟同级传递差不多：</p>

    <Code type='javascript'>{`
    bus.on("dance", function jhonDance(){
    //注意这里多了个global
    this.data.global.set("jhonDanced",true)
})

bus.fire("dance").then(function(){
    //注意这里用的是bus
    console.log( bus.data.global.get("jhonDanced") ) //true
})
    `}</Code>

    <p>无论我们触发的层级有多深，在监听器中使用 `this.data.global` 获取到的都是同一个对象，所以我们也可以用它在不同层级的监听器中传递数据。例如:</p>

    <Code type='javascript'>{`
    bus.on("dance", function jhonDance(){
    //注意这里多了个global
    this.data.global.set("jhonDanced",true)
    //我们在这里再触发一个子事件
    this.fire("sing")
})

bus.on("sing", function mayaSing(){
    //子事件通过 this.data 获取不到上层数据
    console.log( this.data.get("jhonDanced") ) //undefined

    //但是可以通过 this.data.global 获取到
    console.log( this.data.global.get("jhonDanced") ) //true
})


bus.fire("dance")
    `}</Code>

    <p>为什么要使用一个单独的`data`对象来传递数据呢？因为一个事件允许多个监听器监听，每个监听器都有返回值。隐式来约定如何获取返回值不如显示地让开发者自己决定要设置什么数据。</p>

    <h3>直接获取当前事件监听器的data</h3>

    <p>我们可以约定事件与监听器之间的数据。例如，dance 这个事件约定所有监听器往 dancedNames 这个数据里填充数据:</p>

    <Code type='javascript'>{`
    bus.on("dance", function jhonDance(){
    var dancedNames = this.data.get('dancedNames') || []
    dacedNames.push("jhon")
    this.data.set("dancedNames",dacedNames)
})

bus.fire("dance", function(){
    console.log( this.data.get('dancedNames') )
    //["jhon"]
})
    `}</Code>

    <h2>错误处理</h2>

<p>因为一旦出现错误bus内部的运行就会终止，不会有多个错误抛出的情况。所以虽然我们不能通过promise拿到监听器的返回值，但是我们可以直接通过promise 拿到错误对象。</p>

    <Code type='javascript'>{`
    bus.fire().then(function(){},function(err){
    console.log("something wrong",err)
})
    `}</Code>

</Page>




