思想来避免异步回调的嵌套

作者: 前端  发布:2019-11-20

用信号来控制异步流程

2017/08/08 · JavaScript · 异步

原文出处: 十年踪迹   

  • 总结

我们知道,JavaScript 不管是操作 DOM,还是执行服务端任务,不可避免需要处理许多异步调用。在早期,许多开发者仅仅通过 JavaScript 的回调方式来处理异步,但是那样很容易造成异步回调的嵌套,产生 “Callback Hell”。

图片 1

后来,一些开发者使用了 Promise 思想来避免异步回调的嵌套,社区将根据思想提出 Promise/A+ 规范,最终,在 ES6 中内置实现了 Promise 类,随后又基于 Promise 类在 ES2017 里实现了 async/await,形成了现在非常简洁的异步处理方式。

比如 thinkJS 下面这段代码就是典型的 async/await 用法,它看起来和同步的写法完全一样,只是增加了 async/await 关键字。

module.exports = class extends think.Controller { async indexAction(){ let model = this.model('user'); try{ await model.startTrans(); let userId = await model.add({name: 'xxx'}); let insertId = await this.model('user_group').add({user_id: userId, group_id: 1000}); await model.commit(); }catch(e){ await model.rollback(); } } }

1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = class extends think.Controller {
  async indexAction(){
    let model = this.model('user');
    try{
      await model.startTrans();
      let userId = await model.add({name: 'xxx'});
      let insertId = await this.model('user_group').add({user_id: userId, group_id: 1000});
      await model.commit();
    }catch(e){
      await model.rollback();
    }
  }
}

async/await 可以算是一种语法糖,它将

promise.then(res => { do sth. }).catch(err => { some error })

1
2
3
4
5
promise.then(res => {
    do sth.
}).catch(err => {
    some error
})

转换成了

try{ res = await promise do sth }catch(err){ some error }

1
2
3
4
5
6
try{
    res = await promise
    do sth
}catch(err){
    some error
}

有了 async,await,可以写出原来很难写出的非常简单直观的代码:

JS Bin on jsbin.com

function idle(time){ return new Promise(resolve=>setTimeout(resolve, time)) } (async function(){ //noprotect do { traffic.className = 'stop' await idle(1000) traffic.className = 'pass' await idle(1500) traffic.className = 'wait' await idle(500) }while(1) })()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function idle(time){
  return new Promise(resolve=>setTimeout(resolve, time))
}
 
(async function(){
  //noprotect
  do {
    traffic.className = 'stop'
    await idle(1000)
    traffic.className = 'pass'
    await idle(1500)
    traffic.className = 'wait'
    await idle(500)
  }while(1)
})()

上面的代码中,我们利用异步的 setTimeout 实现了一个 idle 的异步方法,返回 promise。许多异步处理过程都能让它们返回 promise,从而产生更简单直观的代码。

网页中的 JavaScript 还有一个问题,就是我们要响应很多异步事件,表示用户操作的异步事件其实不太好改写成 promise,事件代表控制,它和数据与流程往往是两个层面的事情,所以许多现代框架和库通过绑定机制把这一块封装起来,让开发者能够聚焦于操作数据和状态,从而避免增加系统的复杂度。

比如上面那个“交通灯”,这样写已经是很简单,但是如果我们要增加几个“开关”,表示“暂停/继续“和”开启/关闭”,要怎么做呢?如果我们还想要增加开关,人工控制和切换灯的转换,又该怎么实现呢?

有同学想到这里,可能觉得,哎呀这太麻烦了,用 async/await 搞不定,还是用之前传统的方式去实现吧。

其实即使用“传统”的思路,要实现这样的异步状态控制也还是挺麻烦的,但是我们的 PM 其实也经常会有这样麻烦的需求。

我们试着来实现一下:

JS Bin on jsbin.com

function defer(){ let deferred = {}; deferred.promise = new Promise((resolve, reject) => { deferred.resolve = resolve deferred.reject = reject }) return deferred } class Idle { wait(time){ this.deferred = new defer() this.timer = setTimeout(()=>{ this.deferred.resolve({canceled: false}) }, time) return this.deferred.promise } cancel(){ clearTimeout(this.timer) this.deferred.resolve({canceled: true}) } } const idleCtrl = new Idle() async function turnOnTraffic(){ let state; //noprotect do { traffic.className = 'stop' state = await idleCtrl.wait(1000) if(state.canceled) break traffic.className = 'pass' state = await idleCtrl.wait(1500) if(state.canceled) break traffic.className = 'wait' state = await idleCtrl.wait(500) if(state.canceled) break }while(1) traffic.className = '' } turnOnTraffic() onoffButton.onclick = function(){ if(traffic.className === ''){ turnOnTraffic() onoffButton.innerHTML = '关闭' } else { onoffButton.innerHTML = '开启' idleCtrl.cancel() } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
function defer(){
  let deferred = {};
  deferred.promise = new Promise((resolve, reject) => {
    deferred.resolve = resolve
    deferred.reject = reject
  })
  return deferred
}
 
class Idle {
  wait(time){
    this.deferred = new defer()
    this.timer = setTimeout(()=>{
      this.deferred.resolve({canceled: false})
    }, time)
 
    return this.deferred.promise
  }
  cancel(){
    clearTimeout(this.timer)
    this.deferred.resolve({canceled: true})
  }
}
 
const idleCtrl = new Idle()
 
async function turnOnTraffic(){
  let state;
  //noprotect
  do {
    traffic.className = 'stop'
    state = await idleCtrl.wait(1000)
    if(state.canceled) break
    traffic.className = 'pass'
    state = await idleCtrl.wait(1500)
    if(state.canceled) break
    traffic.className = 'wait'
    state = await idleCtrl.wait(500)
    if(state.canceled) break
  }while(1)
  traffic.className = ''
}
 
turnOnTraffic()
 
onoffButton.onclick = function(){
  if(traffic.className === ''){
    turnOnTraffic()
    onoffButton.innerHTML = '关闭'
  } else {
    onoffButton.innerHTML = '开启'
    idleCtrl.cancel()
  }
}

上面这么做实现了控制交通灯的开启关闭。但是实际上这样的代码让 onoffButton、 idelCtrl 和 traffic 各种耦合,有点惨不忍睹……

这还只是最简单的“开启/关闭”,“暂停/继续”要比这个更复杂,还有用户自己控制灯的切换呢,想想都头大!

在这种情况下,因为我们把控制和状态混合在一起,所以程序逻辑不可避免地复杂了。这种复杂度与 callback 和 async/await 无关。async/await 只能改变程序的结构,并不能改变内在逻辑的复杂性。

那么我们该怎么做呢?这里我们就要换一种思路,让信号(Signal)登场了!看下面的例子:

JS Bin on jsbin.com

class Idle extends Signal { async wait(time){ this.state = 'wait' const timer = setTimeout(() => { this.state = 'timeout' }, time) await this.while('wait') clearTimeout(timer) } cancel(){ this.state = 'cancel' } } class TrafficSignal extends Signal { constructor(id){ super('off') this.container = document.getElementById(id) this.idle = new Idle() } get lightStat(){ return this.state } async pushStat(val, dur = 0){ this.container.className = val this.state = val await this.idle.wait(dur) } get canceled(){ return this.idle.state === 'cancel' } cancel(){ this.pushStat('off') this.idle.cancel() } } const trafficSignal = new TrafficSignal('traffic') async function turnOnTraffic(){ //noprotect do { await trafficSignal.pushStat('stop', 1000) if(trafficSignal.canceled) break await trafficSignal.pushStat('pass', 1500) if(trafficSignal.canceled) break await trafficSignal.pushStat('wait', 500) if(trafficSignal.canceled) break }while(1) trafficSignal.lightStat = 'off' } turnOnTraffic() onoffButton.onclick = function(){ if(trafficSignal.lightStat === 'off'){ turnOnTraffic() onoffButton.innerHTML = '关闭' } else { onoffButton.innerHTML = '开启' trafficSignal.cancel() } }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
class Idle extends Signal {
  async wait(time){
    this.state = 'wait'
    const timer = setTimeout(() => {
      this.state = 'timeout'
    }, time)
    await this.while('wait')
    clearTimeout(timer)
  }
  cancel(){
    this.state = 'cancel'
  }
}
 
class TrafficSignal extends Signal {
  constructor(id){
    super('off')
    this.container = document.getElementById(id)
    this.idle = new Idle()
  }
  get lightStat(){
    return this.state
  }
  async pushStat(val, dur = 0){
    this.container.className = val
    this.state = val
    await this.idle.wait(dur)
  }
  get canceled(){
    return this.idle.state === 'cancel'
  }
  cancel(){
    this.pushStat('off')
    this.idle.cancel()
  }
}
 
const trafficSignal = new TrafficSignal('traffic')
 
async function turnOnTraffic(){
  //noprotect
  do {
    await trafficSignal.pushStat('stop', 1000)
    if(trafficSignal.canceled) break
    await trafficSignal.pushStat('pass', 1500)
    if(trafficSignal.canceled) break
    await trafficSignal.pushStat('wait', 500)
    if(trafficSignal.canceled) break
  }while(1)
 
  trafficSignal.lightStat = 'off'
}
 
 
turnOnTraffic()
 
onoffButton.onclick = function(){
  if(trafficSignal.lightStat === 'off'){
    turnOnTraffic()
    onoffButton.innerHTML = '关闭'
  } else {
    onoffButton.innerHTML = '开启'
    trafficSignal.cancel()
  }
}

我们对代码进行一些修改,封装一个 TrafficSignal,让 onoffButton 只控制 traficSignal 的状态。这里我们用一个简单的 Signal 库,它可以实现状态和控制流的分离,例如:

JS Bin on jsbin.com

const signal = new Signal('default') ;(async () => { await signal.while('default') console.log('leave default state') })() ;(async () => { await signal.until('state1') console.log('to state1') })() ;(async () => { await signal.until('state2') console.log('to state2') })() ;(async () => { await signal.until('state3') console.log('to state3') })() setTimeout(() => { signal.state = 'state0' }, 1000) setTimeout(() => { signal.state = 'state1' }, 2000) setTimeout(() => { signal.state = 'state2' }, 3000) setTimeout(() => { signal.state = 'state3' }, 4000)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
const signal = new Signal('default')
 
;(async () => {
    await signal.while('default')
    console.log('leave default state')
})()
 
;(async () => {
    await signal.until('state1')
    console.log('to state1')
})()
 
;(async () => {
    await signal.until('state2')
    console.log('to state2')
})()
 
;(async () => {
    await signal.until('state3')
    console.log('to state3')
})()
 
setTimeout(() => {
    signal.state = 'state0'
}, 1000)
 
setTimeout(() => {
    signal.state = 'state1'
}, 2000)
 
setTimeout(() => {
    signal.state = 'state2'
}, 3000)
 
setTimeout(() => {
    signal.state = 'state3'
}, 4000)

有同学说,这样写代码也不简单啊,代码量比上面写法还要多。的确这样写代码量是比较多的,但是它结构清晰,耦合度低,可以很容易扩展,比如:

JS Bin on jsbin.com

class Idle extends Signal { async wait(time){ this.state = 'wait' const timer = setTimeout(() => { this.state = 'timeout' }, time) await this.while('wait') clearTimeout(timer) } cancel(){ this.state = 'cancel' } } class TrafficSignal extends Signal { constructor(id){ super('off') this.container = document.getElementById(id) this.idle = new Idle() } get lightStat(){ return this.state } async pushStat(val, dur = 0){ this.container.className = val this.state = val if(dur) await this.idle.wait(dur) } get canceled(){ return this.idle.state === 'cancel' } cancel(){ this.idle.cancel() this.pushStat('off') } } const trafficSignal = new TrafficSignal('traffic') async function turnOnTraffic(){ //noprotect do { await trafficSignal.pushStat('stop', 1000) if(trafficSignal.canceled) break await trafficSignal.pushStat('pass', 1500) if(trafficSignal.canceled) break await trafficSignal.pushStat('wait', 500) if(trafficSignal.canceled) break }while(1) trafficSignal.lightStat = 'off' } turnOnTraffic() onoffButton.onclick = function(){ if(trafficSignal.lightStat === 'off'){ turnOnTraffic() onoffButton.innerHTML = '关闭' } else { onoffButton.innerHTML = '开启' trafficSignal.cancel() } } turnRed.onclick = function(){ trafficSignal.cancel() trafficSignal.pushStat('stop') } turnGreen.onclick = function(){ trafficSignal.cancel() trafficSignal.pushStat('pass') } turnYellow.onclick = function(){ trafficSignal.cancel() trafficSignal.pushStat('wait') }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
class Idle extends Signal {
  async wait(time){
    this.state = 'wait'
    const timer = setTimeout(() => {
      this.state = 'timeout'
    }, time)
    await this.while('wait')
    clearTimeout(timer)
  }
  cancel(){
    this.state = 'cancel'
  }
}
 
class TrafficSignal extends Signal {
  constructor(id){
    super('off')
    this.container = document.getElementById(id)
    this.idle = new Idle()
  }
  get lightStat(){
    return this.state
  }
  async pushStat(val, dur = 0){
    this.container.className = val
    this.state = val
    if(dur) await this.idle.wait(dur)
  }
  get canceled(){
    return this.idle.state === 'cancel'
  }
  cancel(){
    this.idle.cancel()
    this.pushStat('off')
  }
}
 
const trafficSignal = new TrafficSignal('traffic')
 
async function turnOnTraffic(){
  //noprotect
  do {
    await trafficSignal.pushStat('stop', 1000)
    if(trafficSignal.canceled) break
    await trafficSignal.pushStat('pass', 1500)
    if(trafficSignal.canceled) break
    await trafficSignal.pushStat('wait', 500)
    if(trafficSignal.canceled) break
  }while(1)
 
  trafficSignal.lightStat = 'off'
}
 
 
turnOnTraffic()
 
onoffButton.onclick = function(){
  if(trafficSignal.lightStat === 'off'){
    turnOnTraffic()
    onoffButton.innerHTML = '关闭'
  } else {
    onoffButton.innerHTML = '开启'
    trafficSignal.cancel()
  }
}
 
turnRed.onclick = function(){
  trafficSignal.cancel()
  trafficSignal.pushStat('stop')
}
 
turnGreen.onclick = function(){
  trafficSignal.cancel()
  trafficSignal.pushStat('pass')
}
 
turnYellow.onclick = function(){
  trafficSignal.cancel()
  trafficSignal.pushStat('wait')
}

Signal 非常适合于事件控制的场合,再举一个更简单的例子,如果我们用一个按钮控制简单的动画的暂停和执行,可以这样写:

JS Bin on jsbin.com

let traffic = new Signal('stop') requestAnimationFrame(async function update(t){ await traffic.until('pass') block.style.left = parseInt(block.style.left || 50) + 1 + 'px' requestAnimationFrame(update) }) button.onclick = e => { traffic.state = button.className = button.className === 'stop' ? 'pass' : 'stop' }

1
2
3
4
5
6
7
8
9
10
11
let traffic = new Signal('stop')
 
requestAnimationFrame(async function update(t){
  await traffic.until('pass')
  block.style.left = parseInt(block.style.left || 50) + 1 + 'px'
  requestAnimationFrame(update)
})
 
button.onclick = e => {
  traffic.state = button.className = button.className === 'stop' ? 'pass' : 'stop'
}

javascript 多线程异步队列

首先,你得知道 jQuery.Deferred 的大致用法,然后,我们进入正题吧:

 

库代码:

 

复制代码

/*!

 * 多线程异步队列

 * 依赖 jQuery 1.8+ (如果你用的是 1.6或1.7, 只要将源码中的 then方法替换为pipe方法 即可)

 */

 

/**

 * @n {Number} 正整数, 线程数量

 */

function Queue (n) {

    n = parseInt(n || 1, 10);

    return (n && n > 0) ? new Queue.prototype.init(n) : null;

}

 

Queue.prototype = {

    init: function (n) {

        this.threads = [];

        this.taskList = [];

 

        while (n--) {

            this.threads.push(new this.Thread)

        }

    },

 

    /**

     * @callback {Fucntion} promise对象done时的回调函数,它的返回值必须是一个promise对象

     */

    push: function (callback) {

        if (typeof callback !== 'function') return;

 

        var index = this.indexOfIdle();

 

        if (index != -1) {

            this.threads[index].idle(callback)

            try { console.log('Thread-' + (index+1) + ' accept the task!') } catch (e) {}

        }

        else {

            this.taskList.push(callback);

 

            for (var i = 0, l = this.threads.length; i < l; i++) {

 

                (function(thread, self, id){

                    thread.idle(function(){

                        if (self.taskList.length > 0) {

                            try { console.log('Thread-' + (id+1) + ' accept the task!') } catch (e) {}

 

                            var promise = self.taskList.pop()();    // 正确的返回值应该是一个promise对象

                            return promise.promise ? promise : thread.promise;

                        } else {

                            return thread.promise

                        }

                    })

                })(this.threads[i], this, i);

 

            }

        }

    },

    indexOfIdle: function () {

        var threads = this.threads,

            thread = null,

            index = -1;

 

        for (var i = 0, l = threads.length; i < l; i++) {

            thread = threads[i];

 

            if (thread.promise.state() === 'resolved') {

                index = i;

                break;

            }

        }

 

        return index;

    },

    Thread: function () {

        this.promise = $.Deferred().resolve().promise();

 

        this.idle = function (callback) {

            this.promise = this.promise.then(callback)

        }

    }

};

 

Queue.prototype.init.prototype = Queue.prototype;

复制代码

使用示例:

 

复制代码

    var queue = new Queue(3);    // 创建一个具有3个线程的队列

 

  // task-1

    queue.push(function(){

        var defer = $.Deferred();

 

        setTimeout(function(){

            defer.resolve()

        }, 8000);

 

        return defer.promise()

    })

 

  // task-2

    queue.push(function(){

        var defer = $.Deferred();

 

        setTimeout(function(){

            defer.resolve()

        }, 2000);

 

        return defer.promise()

    })

 

  // task-3

    queue.push(function(){

        var defer = $.Deferred();

 

        setTimeout(function(){

            defer.resolve()

        }, 6000);

 

        return defer.promise()

    })

 

  // task-4

    queue.push(function(){

        var defer = $.Deferred();

 

        setTimeout(function(){

            defer.resolve()

        }, 3000);

 

        return defer.promise()

    })

 

  // task-5

    queue.push(function(){

        var defer = $.Deferred();

 

        setTimeout(function(){

            defer.resolve()

        }, 2000);

 

        return defer.promise()

    })

 

  // task-6

    queue.push(function(){

        var defer = $.Deferred();

 

        setTimeout(function(){

            defer.resolve()

        }, 2000);

 

        return defer.promise()

    })

复制代码

控制台有显示 queue.push的 function (暂且叫它task)  最终是哪个进程处理的

 

实例化后,队列里的3个线程都是处于空闲状态的

将task-1分配给线程1, 这个任务耗时 8s

将task-2分配给线程2, 这个任务耗时 2s

将task-3分配给线程3, 这个任务耗时 6s

 

因为当前没有空闲进程,队列内部则将task-4、task-5、task-6添加到等候区

 

因为task-2耗时2s,进程2最先被解放,然后task-4就被分配到进程2去处理,以此类推,最后控制台显示的进程使用情况是:1、2、3、2、2、3

 

 

 

这个库的使用场景是这样的

1、如本人最近做的项目:

主播在做直播,很多观众会给主播送礼物,这些礼物都是有js动画特效的,页面中最多可以同时显示三个礼物特效

 

2、相互依赖的异步请求

a请求依赖b请求,b请求依赖c请求,c请求依赖。。。

这个需求我们就可以使用这个库这样实现:

 

复制代码

var queue = new Queue(1);

 

// request c

queue.push(function(){

    return $.ajax();    // jq 的ajax返回的正是 promise对象

})

 

// request b

queue.push(function(){

    return $.ajax();

})

 

// request a

queue.push(function(){

    return $.ajax();

})

复制代码

 queue.push(callback)   callback必须返回一个promise对象

 

多线程异步队列 首先,你得知道 jQuery.Deferred 的大致用法,然后,我们进入正题吧: 库代码: 复制代码 /*! * 多线程异步队列 * 依...

详细参数可查询MSDN

总结

我们可以用 Signal 来控制异步流程,它最大的作用是将状态和控制分离,我们只需要改变 Signal 的状态,就可以控制异步流程,Signal 支持 until 和 while 谓词,来控制状态的改变。

可以在 GitHub repo 上进一步了解关于 Signal 的详细信息。

1 赞 收藏 评论

图片 2

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<link href="style/style.css" rel="stylesheet" type="text/css">

<script language="JavaScript">
var state;

//初始化
function playerinit()
{
 player.url="mp3.m3u";
 player.settings.autoStart = false ;
}

//播放
function play()
{
 if (player.controls.isavailable('play'))
 {
  player.controls.play();
  state=setInterval("updatetime()",1000);
  playerinfo.innerHTML = "播放";
 }
}

//暂停
function pause()
{
 if (player.controls.isavailable('pause'))
 {
  player.controls.pause();
  clearInterval(state);
  playerinfo.innerHTML = "暂停";
 }
}

//停止
function stop()
{
 if (player.controls.isavailable('stop'))
 {
  player.controls.stop();
  clearInterval(state);
  playerinfo.innerHTML = "停止";
 }
}

//前首
function previous()
{
 if (player.controls.isavailable( 'previous' ))
 {
  player.controls.previous();
  playerinfo.innerHTML = "前一首";
 }
}

//后首
function next()
{
 if (player.controls.isavailable( 'next' ))
 {
  player.controls.next();
  playerinfo.innerHTML = "下一首";
 }
}

//?
function step()
{
 if (player.controls.isavailable( 'step' ))
 player.controls.step( 1 );
}

//音量-
function voldown()
{
 if ( player.settings.volume < 5 )
 {
  player.settings.volume = 0;
  playerinfo.innerHTML = "0";
 }
 else
 {
  player.settings.volume -= 5;
  playerinfo.innerHTML = player.settings.volume;
 }
}

//音量+
function volup()
{
 if ( player.settings.volume > 95 )
 {
  player.settings.volume = 100;
  playerinfo.innerHTML = "100";
 }
 else
 {
  player.settings.volume += 5;
  playerinfo.innerHTML = player.settings.volume;
 }
}

//静音
function mute()
{
 player.settings.mute = !player.settings.mute;
}

//声道
function balance()
{
 switch (player.settings.balance)
 {
  case 0:
   player.settings.balance = 100;
   playerinfo.innerHTML = '左声道';
   break;
  case 100:
   player.settings.balance = -100;
   playerinfo.innerHTML = '右声道';
   break;
  case -100:
   player.settings.balance = 0;
   playerinfo.innerHTML = '全声道';
   break;
  default :
   player.settings.balance = 0;
   playerinfo.innerHTML = '全声道';
   break;
 }
}

//更新时间
function updatetime()
{
 playerinfo.innerHTML = player.controls.currentPositionString + " | " + player.currentMedia.durationString;
}

</script>
</head>
<body onload="playerinit();">
<table width="300">
  <tr>
    <td><object id="player" classid="CLSID:6BF52A52-394A-11d3-B153-00C04F79FAA6" type="application/x-oleobject" width="300" height="60">
      <param name="autoStart" value="false">
      <param name="balance" value="0">
      <param name="currentPosition" value="0">
      <param name="currentMarker" value="0">
      <param name="enableContextMenu" value="true">
      <param name="enableErrorDialogs" value="false">
      <param name="enabled" value="true">
      <param name="fullScreen" value="false">
      <param name="invokeURLs" value="false">
      <param name="mute" value="true">
      <param name="playCount" value="1">
      <param name="rate" value="1">
      <param name="uiMode" value="none">
      <param name="volume" value="100">
    </object></td>
  </tr>
  <tr>
    <td><span id="playerinfo"></span></td>
  </tr>
  <tr>
    <td>
      <div align="center">
<input type="button" class="but11" onmouseover=this.className="but12"; onmouseout=this.className="but11"; name="previous" title="上一首" onclick="previous();">
<input type="button" class="but21" onmouseover=this.className="but22"; onmouseout=this.className="but21"; name="play" title="播放" onclick="play();">
<input type="button" class="but31" onmouseover=this.className="but32"; onmouseout=this.className="but31"; name="pause" title="暂停" onclick="pause();">
<input type="button" class="but41" onmouseover=this.className="but42"; onmouseout=this.className="but41"; name="stop" title="停止" onclick="stop();">
<input type="button" class="but51" onmouseover=this.className="but52"; onmouseout=this.className="but51"; name="next" title="下一首" onclick="next();">
<input type="button" class="but61" onmouseover=this.className="but62"; onmouseout=this.className="but61"; name="voldown" title="音量-" onclick="voldown();">
<input type="button" class="but61" onmouseover=this.className="but62"; onmouseout=this.className="but61"; name="volup" title="音量+" onclick="volup();">
<input type="button" class="but61" onmouseover=this.className="but62"; onmouseout=this.className="but61"; name="mute" title="静音" onclick="mute();">
<input type="button" class="but61" onmouseover=this.className="but62"; onmouseout=this.className="but61"; name="balance" title="声道" onclick="balance();">
   </div>
 </td>
  </tr>
</table>
<script language = "JavaScript"  for = player event = playstatechange(newstate)>
switch (newstate){
  case 1:
   playerinfo.innerHTML = "停止";
   break;
  case 2:
   playerinfo.innerHTML = "暂停";
   break;
  case 3:
   playerinfo.innerHTML = "正在播放";
   break;
  case 4:
   playerinfo.innerHTML = "4";
   break;
  case 5:
   playerinfo.innerHTML = "5";
   break;
  case 6:
   playerinfo.innerHTML = "正在缓冲...";
   break;
  case 7:
   playerinfo.innerHTML = "7";
   break;
  case 8:
   playerinfo.innerHTML = "8";
   break;
  case 9:
   playerinfo.innerHTML = "正在连接...";
   break;
  case 10:
   playerinfo.innerHTML = "准备就绪。欢迎光临<a href=';";
   break;
  case 11:
   playerinfo.innerHTML = "11";
   break;
  default:
   playerinfo.innerHTML = "";
}
</script>

</body>
</html>

!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional...

本文由9159.com发布于前端,转载请注明出处:思想来避免异步回调的嵌套

关键词:

上一篇:没有了
下一篇:没有了