js 异步&Promise
主任务 | 任务队列 |
---|---|
主任务只有一个
主任务运行结束后,会从任务队列中寻找任务执行
主(同步)任务、promise、宏任务、微任务
setTimeout():属于宏任务。
console.log():属于主任务。
new Promise():里面的
resolve => {
resolve();//或reject()
console.log(“promise”);
}:属于主任务。
.then(()=>{},()=>{}):属于微任务,只有当resolve、reject有一执行时,.then()才会执行。
**任务执行顺序:**主任务、微任务、宏任务。
微任务包括 process.nextTick
,promise
,Object.observe
,MutationObserver
宏任务包括 script
, setTimeout
,setInterval
,setImmediate
,I/O
,UI rendering
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HJ1TpKhr-1585212783289)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1585037163946.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1KiKRoq0-1585212783293)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1585037430994.png)]
Promise.then()的返回值也是一个Promise对象
1.前一个回调函数,有可能返回的还是一个Promise
对象(即有异步操作),这时后一个回调函数,就会等待该Promise
对象的状态发生变化,才会被调用。console.log®就需要等到上一个Promise状态返回。
let p1 = new Promise((resolve, reject) => {
// reject("fail");
resolve("fulfilled");
})
.then(
value => {
// return "houdunren";
console.log(value)
return new Promise((resolve, reject) => {
// resolve("解决了");
setTimeout(() => {
reject("处理失败");
}, 3000);
}).then(null, r => {
console.log(r)
return new Promise((resolve, reject) => {
reject("失败了。。。。");
});
});
},
reason => console.log("erorr" + reason)
)
.then(
value => {
console.log("成功:" + value);
},
reason => console.log("error" + reason)
);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SJ6CkXfY-1585212783297)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1585052210938.png)]
2.当then()方法没有返回Promise的状态,就默认是resolve()
let p1 = new Promise((resolve, reject) => {
// resolve("fulfilled");
reject("rejected");
});
let p2 = p1
.then(
value => console.log(value),
reason => console.log(reason)
)
.then(
a => console.log("成功"),
b => console.log(b)
);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m3ay5l8k-1585212783298)(C:\Users\asus\AppData\Roaming\Typora\typora-user-images\1585052058259.png)]
其它类型的Promise封装
下面展示了三种类型的封装:只要你返回的对象里面有Promise或then里面包含(resolve,reject),且里面返回了状态,就可以。
let p1 = new Promise((resolve, reject) => {
resolve("fulfilled");
})
.then(
value => {
// class Hd {
// then(resolve, reject) {
// setTimeout(() => {
// resolve("这是对象");
// }, 2000);
// }
// }
// return new Hd()
//======================
// return then(resolve,reject){
// resolve("成功")
// }
//======================
return class {
static then(resolve, reject) {
// resolve("这是一个静态方法");
reject("失败");
}
};
},
reason => {}
)
.then(
value => {
console.log(value);
},
reason => {
console.log(reason);
}
);
Promise.prototype.catch()
catch()其实与then()的第二个参数功能类似
p.then((val) => console.log('fulfilled:', val))
.catch((err) => console.log('rejected', err));
// 等同于
p.then((val) => console.log('fulfilled:', val))
.then(null, (err) => console.log("rejected:", err));
比较下面两种写法,可以发现reject
方法的作用,等同于抛出错误
// 写法一
const promise = new Promise(function(resolve, reject) {
try {
throw new Error('test');
} catch(e) {
reject(e);
}
});
//也可以用promise.then(null,reason=>{console.log(reason)})
promise.catch(function(error) {
console.log(error);
});
// 写法二
const promise = new Promise(function(resolve, reject) {
reject(new Error('test'));
});
promise.catch(function(error) {
console.log(error);
});
一般来说,不要在then
方法里面定义 Reject 状态的回调函数(即then
的第二个参数),总是使用catch
方法。
Promise 对象的错误具有“冒泡”性质,会一直向后传递,直到被捕获为止。也就是说,错误总是会被下一个catch
语句捕获。
// bad
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
上面代码中,第二种写法要好于第一种写法,理由是第二种写法可以捕获前面then
方法执行中的错误,也更接近同步的写法(try/catch
)。因此,建议总是使用catch
方法,而不使用then
方法的第二个参数。
Promise对象里面的错误,不管有没有then()第二个参数或catch接受,会报错但不会影响后面的代码执行,其实也好理解,仅仅就是没有捕获错误,并不会影响代码执行。
待更新…