promise and async
js设计初衷是应用于浏览器端,为了避免用户交互时候的冲突,js是单线程的,为了解决js中的很多异步场景的问题。
//最常见的一种回调的嵌套:---回调地狱
doAsyncJob1(function(){
doAsyncJob2(function(){
doAsyncJob3(function(){
doAsyncJob4(function(){
//Black hole
});
})
});
});
es6以及之后提案提出了几个解决方案。以下是对这几个异步解决方案的简单理解。
promise
promise 类似于不可逆的状态机。只能pengding到fulfilled或者到rejected。
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
promise.then(function(value){
console.log(value)
},function(error){
console.log(error)
})
关键点
- resolve 和 reject为内置函数,then函数内部是回调函数(可分别接受resolve和reject的回调),resolve和reject可以分别传参给这两个函数。
- 举一个可以解决请求的回调嵌套的例子
const p1 = new Promise(function(resolve,reject){
....
})
const p2 = new Promise(function(resolve,reject){
resolve(p1)
})
- p2的执行依赖于p1的执行结果。
- resolve或者reject并不会阻止promise内部剩余其他代码的执行。
- promise.then返回一个新的promise对象,可以链式调用。像二中的代码可以写成promise.then().then().then()...的形式。
- 错误处理(reject状态处理),catch方法里处理更加推荐(语义化)。
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
- 另外还有两个很有用的方法:
//promise.all:所有请求同时发送,都成功之后resolve。
// 多个请求可以同时处理时候性能提升显著
promise.all([p1,p2,p3],function{
})
// 第一个成功之后resolve,并且回调函数返回一个基于该成功的promise对象。
promise.race
不足之处
- 一旦开始无法结束
- 会吃掉错误,如果没有相应回调来处理错误,promise错误不会传递到外层。
async
async 是js实现异步的另一种方式,本质上是generate函数的语法糖。 它返回一个promise对象,可以调用then方法对返回的内容进行处理。gennerate需要手动调用一个指向内部的指针,来进行异步操作(详见),而async则不用。
//
const asyncReadFile = async function () {
const f1 = await readFile('/etc/fstab');//等我执行完
const f2 = await readFile('/etc/shells');//等我也执行完再打印
console.log(f1.toString());
console.log(f2.toString());
};
函数内部await引导的异步操作会同步执行。async函数返回一个promise对象,可以使用then对返回值进行处理,错误处理也同promise。
await命令
await命令后边是一个promise对象,如果不是那就会被转化成一个状态为resolve的promise对象。
错误处理以及使用注意
async function f() {
await Promise.reject('出错了');
await Promise.resolve('hello world'); // 不会执行
}
解决办法:
- 在内部catch(err);
async function f() {
await Promise.reject('出错了')
.catch(e => console.log(e));
return await Promise.resolve('hello world');
}
f()
.then(v => console.log(v))
// 出错了
// hello world
- 可能reject的代码写在try,catch中。
async function main() {
try {
const val1 = await firstStep();
const val2 = await secondStep(val1);
const val3 = await thirdStep(val1, val2);
console.log('Final: ', val3);
}
catch (err) {
console.error(err);
}
}
- 灵活应用promise.all进行并行处理,提升性能