以同步方式编写异步代码的解决方案实质上只是改变了代码编写方式,简化和优化代码的写法,使开发人员以更优雅的方式编写异步代码,以解决异步代码的流程控制问题,降低了异步编程难度。但程序本质上还是异步执行的,这些方案并没有对程序本身进行优化,也没有提高应用程序性能。
一、Promise
1、什么是Promise
Promise对象代表一个异步操作,有以下3种状态。
等待(Pending):初始状态,没有实现也没有被拒绝。
实现(Fulfilled):操作已成功完成。
被拒绝(Rejected):操作失败。
只有异步操作的结果才可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
简化回调嵌套只是Promise的一项基本功能,Promise最关键的是状态,Promise通过维护和传递状态的方式使回调函数能够及时被调用,这比直接传递回调函数要简单和灵活得多。
2、创建Promise对象
let promise = new Promise((resolve, reject)=>{
//执行异步操作代码
if (/*成功*/){
resolve(value);//异步操作执行成功后的回调函数
}else {
reject(error);//异步操作执行失败后的回调函数
});
3、Promise的方法
then()
promise.then((value)=>{ //成功
console.log(成功,value);
},(error)=>{ //失败
console.err(失败,error);
})
catch()
promise.then((value)=>{
console.log(成功,value);
}).catch((error)=>{
console.err(失败,error);
})
Promise.resolve()
Promise.reject()
Promise.all()
var promise1= Promise.resolve(70);
var promise2= 82;
var promise3= new Promise(function(resolve){
setTimeout(resolve,1000,95);//1秒钟之后执行
});
Promise.all([promise1, promise2, promise3]).then(function(values){
console.log(values);
});//输出数组:[ 70,82,95]
Promise.race()
二、Generator
1、什么是Generator
Generator是一个生成器,同时也是一个状态机,其内部拥有值和相关状态。
生成器返回一个迭代器(Iterator)对象,可以编写程序通过该对象遍历相关的值和状态,以保证正确的执行顺序。
Generator本质上是一个函数,其最大的特点是可以被中断,然后再恢复执行。
Promise对象创建之后,就会处于等待状态并开始执行,直到状态改变之后才能进行下一步操作。
Generator函数可以由用户执行中断,去执行其他操作,然后从中断处恢复执行。
2、Generator函数声明及其执行
function* genFunc(score){ //声明Generator函数声明
yield 积分+score;
yield 积分+(score +10);
return 积分+(score +20);
yield 积分+(score +30);
}
var gen = genFunc(10);//调用之后返回了一个迭代器对象
console.log(gen.next());//返回对象{ value:积分10, done: false }
console.log(gen.next());//返回对象{ value:积分20, done: false }
console.log(gen.next());//返回对象{ value:积分30, done: false }
console.log(gen.next());//返回对象{ value: undefined, done: true }
3、调用Generator对象
调用Generator对象有两种方法。
不断地调用next()方法。next()方法会执行Generator的代码,每次遇到yield就返回一个对象(形式为{value: x, done: true/false}),然后“暂停”,返回的value就是yield的返回值,done表示该Generator对象是否已经执行结束了。
直接用循环语句for … of自动遍历Generator对象。
for (let obj of gen){
console.log(obj);
break;//关闭迭代器,触发return
}//最终返回:积分10
4、使用Generator解决异步回调问题
可以将异步操作写在yield语句中,在调用next()方法后再向后执行。
yield除了使用表达式之外,还可以使用Promise对象。由yield对表达式求值并返回,调用next()方法会返回一个Promise对象,接着调用then()方法,并在回调函数中通过next()方法将结果传回Generator。Generator与Promise对象联合使用,大大改进异步代码编写流程。
三、co模块
1、co模块实现思路
co模块将Generator函数包装成一个Promise对象,作为参数传递给co()方法,在co()方法内部自动执行yield,以将异步操作改为“顺序”执行。co()方法包括一个Generator函数,co()方法在Generator函数中使用yield指向Promise对象,通过递归调用next()方法将每一个Promise的值返回,从而实现异步转“同步”的代码编写方式。
co()方法返回一个Promise对象,可以调用then()和catch()方法对Generator函数返回的结果进行传递,以方便后续的成功处理或者错误处理。
2、co模块的基本使用
要使用co模块,需要安装相应的包:
npm install co
然后在程序中导入该模块:
const co = require(co);
示例: co返回一个Promise对象
co(function*(){ //声明一个co-generator函数
var result = yield Promise.resolve(true);
return result;
}).then(function (value){
console.log(value);
}, function (err){
console.error(err.stack);
});
3、可用的yield对象
co模块目前支持的对象类型
Promise
Thunks(函数)
数组(并行执行)
对象(并行执行)
Generator(代理)
Generator函数(代理)
对象嵌套
数组用于并行完成所有的yield异步操作:
co(function*(){
var res = yield [
Promise.resolve(路人甲),
Promise.resolve(路人乙),
];
console.log(res);//=>[路人甲,路人乙]
});
对象用于并行处理:
co(function*(){
var res = yield {
男配: Promise.resolve(路人甲),
女配: Promise.resolve(路人乙),
};
console.log(res);//返回: {男配:路人甲,女配:路人乙}
});
4、co模块的错误捕获
const co = require(co);
co(function *(){
try {
yield Promise.reject(new Error(发生错误!));
} catch (err){
console.error(err.message);//”发生错误!”
}
}).catch(onerror);
function onerror(err){
//记录未捕获的错误,co模块不会抛出未处理的任何错误,需要自己处理所有错误
console.error(err.stack);
}
暂无评论内容