异步编程的几种模式
回调和事件
Promise
Async,Wait
Promise
Promise 是 ES6 提供的原生类,简单的说就是一个容器,里面保存着某个异步执行的操作结果(也就是说未来才会获得的结果)。类似于Java 中的 Future 类。
三种状态:pending(进行中),fulfilled(成功, resolved),rejected(失败)
状态变化:
- pending => fulfilled
- pending => rejected
有了 Promise 对象,就可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数。
缺点:
- 无法取消,一旦新建就会立即执行;
- 如果不设置回调函数,Promise 内部会抛出错误;
- 当出于 pending 状态时,无法得知目前进展到哪一个阶段;
示例 1:
let start = new Date().getTime();
let log = (msg) => console.log(msg + " - " + (new Date().getTime() - start))
log("mark 1");
let p = new Promise((res, rej)=> {
log("mark 2");
res("mark 5");
log("mark 3");
})
p.then((value)=>log(value));
p.then((value)=>log(value));
log("mark 4");
示例 2
console.log("mark 1");
let p = new Promise((res, rej)=> {
console.log("mark 2");
let out = ()=>{
console.log("xxxx");
res("vava");
}
setTimeout(()=>{ res("mark 5")}, 2000,);
console.log("mark 3");
})
p.then((value)=>console.log(value));
p.then((value)=>console.log(value));
console.log("mark 4");
说明:
- 从外部看来,Promise 的创建不会导致程序阻塞;
- 调用 then 方法,出入的回调函数会被延迟执行;
- then 方法可以重复调用;
- then(success, fail):then 方法可以接受两个回调函数作为参数,第一个回调函数在 Promise 对象的状态变为 resolved 时调用,第二个回调函数在 Promise 对象的状态转变为 rejected 时调用。
MyPromise
可以通过下面的自定义类,来模拟 Promise 的行为:
class MyPromise{
constructor(callback){
let res = (params)=> this.res(params); // 这里使用了类似拦截器或者代理的效果,对目标 res 进行包裹
let rej = (params)=> this.rej(params);
this.status = 0; // pending
this.actions = [];
this.params = null;
callback(res, rej); // 当创建 MyPromise 对象时,立即调用传入的回调方法;
}
// 实际的 res,rej 函数实例是通过 then 函数传进来的
then(res, rej){
if (this.status === 0){ // 如果处在 pending 状态,就将 res,rej 回调方法缓存起来,等有结果了再调
this.actions.push([res, rej]);
return;
}
if (this.status === 1){
res(this.params);
return;
}
if (this.status === 2){
rej(this.params);
}
}
res(params){
this.params = params;
this.status = 1; // fullfiled
this.actions.forEach(action=> action[0](params));
}
rej(params){
this.params = params;
this.status = 2; // rejected
this.actions.forEach(action=> action[1](params));
}
}