乐趣区

JavaScript-异步编程

Callback

场景一

在微信小程序中,我们对请求做了一层封装,如果请求时,检测到没有 token 或者token 已过期,则需要重新调用 刷新 token 方法,更新 token 后再去请求,然而我们打开微信小程序首页,此时可能并发多个请求,就会出现多次请求刷新 token 方法,我们 需求 是:在第一个请求刷新 token 后再执行后面的业务请求

模拟代码:

function requestA(){setTimeout(()=>{console.log('requestA')
  },1000)
}
function requestB(){setTimeout(()=>{console.log('requestB')
  },800)
}
function requestC(){setTimeout(()=>{console.log('requestC')
  },600)
}
function requestD(){setTimeout(()=>{console.log('requestD')
  },400)
}
function requestE(){setTimeout(()=>{console.log('requestE')
  },200)
}

requestA 改造:

// 对 requestA 进行 回调 改变
function requestA(callback){setTimeout(()=>{console.log('requestA')
    callback && callback()},1000)
}

执行:

requestA(()=>{requestB()
  requestC()
  requestD()
  requestE()})

场景二:

多个请求逐层向上依赖上个请求的数据

示例:

function requestA(callback){setTimeout(()=>{callback && callback('requestA 请求的结果')
  },1000)
}
function requestB(ret,callback){if(ret === 'requestA 请求的结果'){setTimeout(()=>{callback && callback('requestB 请求的结果')
    },800)
  }
}
function requestC(ret,callback){if(ret === 'requestB 请求的结果'){setTimeout(()=>{callback && callback('requestC 请求的结果')
    },600)
  }
}
function requestD(ret,callback){if(ret === 'requestC 请求的结果'){setTimeout(()=>{callback && callback('requestD 请求的结果')
    },400)
  }
}
function requestE(ret,callback){if(ret === 'requestD 请求的结果'){setTimeout(()=>{callback && callback('requestE 请求的结果')
    },200)
  }
}

执行:

requestA(ret=>{console.log(ret)
    requestB('requestA 请求的结果',ret=>{console.log(ret)
        requestC('requestB 请求的结果',ret=>{console.log(ret)
            requestD('requestC 请求的结果',ret=>{console.log(ret)
                requestE('requestD 请求的结果',ret=>{console.log(ret) 
                })
            })
        })
    }) 
})

依次打印出了:

requestA 请求的结果 ->requestB 请求的结果 ->requestC 请求的结果 ->requestD 请求的结果 ->requestE 请求的结果

Promise

场景:多个请求逐层向上依赖上个请求的数据,用 promise 改造

function requestA(){return new Promise((resolve,reject)=>{setTimeout(()=>{resolve('requestA 请求的结果')
        },1000)
    })
}
function requestB(param){return new Promise((resolve,reject)=>{if(param==='requestA 请求的结果'){setTimeout(()=>{resolve('requestB 请求的结果')
            },800)
        }else{reject('requestB 请求失败')
        }
        
    })
}
function requestC(param){return new Promise((resolve,reject)=>{if(param==='requestB 请求的结果'){setTimeout(()=>{resolve('requestC 请求的结果')
            },600)
        }else{reject('requestC 请求失败')
        }
        
    })
}

function requestD(param){return new Promise((resolve,reject)=>{if(param==='requestC 请求的结果'){setTimeout(()=>{resolve('requestD 请求的结果')
            },400)
        }else{reject('requestD 请求失败')
        }
        
    })
}
function requestE(param){return new Promise((resolve,reject)=>{if(param==='requestD 请求的结果'){setTimeout(()=>{resolve('requestE 请求的结果')
            },200)
        }else{reject('requestE 请求失败')
        }
    })
}

使用:

requestA()
.then(ret=>requestB(ret))
.then(ret=>requestC(ret))
.then(ret=>requestD(ret))
.then(ret=>requestE(ret))
.then(ret=>{console.log(ret)//requestE 请求的结果
}).catch(err=>{console.log(err)
})

Generator

模拟请求:

function requestA(){return new Promise((resolve,reject)=>{setTimeout(()=>{resolve('requestA 请求的结果')
        },1000)
    })
}
function requestB(param){return new Promise((resolve,reject)=>{if(param==='requestA 请求的结果'){setTimeout(()=>{resolve('requestB 请求的结果')
            },800)
        }else{reject('requestB 请求失败')
        }
        
    })
}
function requestC(param){return new Promise((resolve,reject)=>{if(param==='requestB 请求的结果'){setTimeout(()=>{resolve('requestC 请求的结果')
            },600)
        }else{reject('requestC 请求失败')
        }
        
    })
}

function requestD(param){return new Promise((resolve,reject)=>{if(param==='requestC 请求的结果'){setTimeout(()=>{resolve('requestD 请求的结果')
            },400)
        }else{reject('requestD 请求失败')
        }
        
    })
}
function requestE(param){return new Promise((resolve,reject)=>{if(param==='requestD 请求的结果'){setTimeout(()=>{resolve('requestE 请求的结果')
            },200)
        }else{reject('requestE 请求失败')
        }
    })
}

Generator的异步使用:

function* gen(){let result = yield requestA();
    // console.log(result+'result')

    let result1 = yield requestB(result);
    // console.log(result1+'result1')

    let result2 = yield requestC(result1);
    // console.log(result2+'result2')

    let result3 = yield requestD(result2);
    // console.log(result3+'result3')

    let result4 = yield requestE(result3);
    // console.log(result4+'result4')
    return result4
}

var g = gen();

var result = g.next();

result.value.then(function(data){console.log(data+'requestA 请求的数据')
    return  g.next(data).value
    
}).then(function(data){console.log(data+'requestB 请求的数据')
    return g.next(data).value
  
}).then(function(data){console.log(data+'requestC 请求的数据')
    return g.next(data).value
  
}).then(function(data){console.log(data+'requestD 请求的数据')
   return g.next(data).value
 
}).then(function(data){console.log(data+'requestE 请求的数据')
 
})

Async

模拟请求:

function requestA(){return new Promise((resolve,reject)=>{setTimeout(()=>{resolve('requestA 请求的结果')
        },1000)
    })
}
function requestB(param){return new Promise((resolve,reject)=>{if(param==='requestA 请求的结果'){setTimeout(()=>{resolve('requestB 请求的结果')
            },800)
        }else{reject('requestB 请求失败')
        }
        
    })
}
function requestC(param){return new Promise((resolve,reject)=>{if(param==='requestB 请求的结果'){setTimeout(()=>{resolve('requestC 请求的结果')
            },600)
        }else{reject('requestC 请求失败')
        }
        
    })
}

function requestD(param){return new Promise((resolve,reject)=>{if(param==='requestC 请求的结果'){setTimeout(()=>{resolve('requestD 请求的结果')
            },400)
        }else{reject('requestD 请求失败')
        }
        
    })
}
function requestE(param){return new Promise((resolve,reject)=>{if(param==='requestD 请求的结果'){setTimeout(()=>{resolve('requestE 请求的结果')
            },200)
        }else{reject('requestE 请求失败')
        }
    })
} 

Async的异步使用:

async function init(){let ret1 =await requestA()
    let ret2 =await requestB(ret1)
    let ret3 =await requestC(ret2)
    let ret4 =await requestD(ret3)
    let ret5 =await requestE(ret4)
    return ret5
}

init().then(res=>{console.log(res)//requestE 请求的结果
}).catch(err=>{console.log(err)
})

事件监听

脚本的执行不取决代码的顺序,而取决于某一个事件是否发生。

案列:

$(document).ready(function(){console.log('DOM 已经 ready')
});

发布 / 订阅

发布 / 订阅模式是利用一个消息中心,发布者发布一个消息给消息中心,订阅者从消息中心订阅该消息

案例:

// 订阅 done 事件
$('#box').on('done',function(data){console.log(data)
})
// 发布事件
$('#box').trigger('done,'data')
退出移动版