在js学习过程中对js中的各种异步进行一个个人的总结
- js异步(一)Promise 理解总结
- ji异步(二)async / await 理解总结
Promise使用原因
因为JavaScript是单线程,在Promise未出现之时如果想要实现异步操作,最常用的方法是使用回调函数,在有很多层回调时就会陷入回调地狱,使得代码变得难以阅读和维护。Promise的出现正是为了解决这个问题,将异步过程和对结果的处理分离。本质上,Promise 是一个绑定了回调的对象,而不是将回调传进函数内部。
Promise基本用法
function timeout(n) {
return new Promise((resolve, reject) => {
// 一些异步操作
setTimeout(() => {
// 异步操作成功后执行
resolve('timeout Promise');
}, n)
// 异步操作失败后执行
reject('timeout failed');
})
}
timeout(1000)
.then(result => {
console.log(result);
}, error => {
console.log(error);
});
// timeout Promise
Promise构造函数接受一个有两个参数的函数作为参数,resolve为异步操作执行成功后的处理函数,参数为想要向处理函数传递的参数,reject为异步操作失败时执行的函数。
Promise三种状态
- pending (初始化/待定,尚未执行或拒绝)
- resolved(已执行,与 promise 相关的操作成功)
- rejected(已拒绝,与 promise 相关的操作失败)
resolve函数将Promise对象的状态从 pending 变为 resloved,reject函数将Promise对象的状态冲 pending 变为 rejected。Promise 实例生成后,可以用then方法可以指定resolve和reject函数,它的第一个参数为resolve函数,第二个参数为reject函数,其中第二个参数可选,也可以将第二个参数拿出来作为catch(二者区别相见错误处理部分)
timeout(1000)
.then(result => {
console.log(result);
}).catch( error => {
console.log(error);
})
- Promise 只能成功或失败一次,不能成功或失败两次,已不能从成功转为失败或从失败转为成功
相当于一个状态机,只能从 pending 转为 resloved/rejected,一旦修改就不能改变,而且执行了一个就不会继续执行下一个了,之前的例子中,setTimeout成功之后,即使写了reject('timeout failed')也不会执行。
调用时间
首先改一下之前的代码
function timeout(n) {
return new Promise((resolve, reject) => {
console.log('new Promise');
// 一些异步操作
setTimeout(() => {
resolve('timeout Promise');
}, n)
reject('timeout failed');
})
}
timeout(1000)
.then(result => {
console.log(result);
}).catch( error => {
console.log(error);
});
console.log('after timeout');
// new Promise
// after timeout
// timeout Promise
Promise 属于任务队列中的微任务,根据JavaScript事件循环,Promise在新建后立即执行,而 then 函数指定的回调函数在当前脚本所有同步任务执行完才会执行。
链式调用
then 函数中可以仍旧返回一个 Promise 对象,实现链式操作
function timeout(n) {
return new Promise((resolve, reject) => {
// 一些异步操作
setTimeout(() => {
resolve(n + 200);
}, n)
})
}
// 链式调用
const time1 = 500;
timeout(time1)
.then(time2 => {
console.log(time1, time2);
return timeout(time2).then( time3 => [time1, time2, time3]);
})
.then(times => {
const [time1, time2, time3] = times;
console.log(time1, time2, time3);
return timeout(time3);
})
.then(result => {
console.log('result', result);
})
// 500 700
// 500 700 900
// result 1100
注:一定要有返回(即 return),否则 callback 无法获取上一个 Promise 的结果。
错误处理
使用 catch 可以在一个回调失败后继续使用链式操作
new Promise((resolve, reject) => {
console.log('initial');
resolve();
})
.then(() => {
throw new Error('Something failed');
console.log('do this');
})
.catch(() => {
console.log('do that');
})
.then(() => {
console.log('do this whatever happened before');
})
// initial
// do that
// do this whatever happened before
如果写成 then( func1, func2)形式,则 func1 或 func2 中的一个将被调用,而不会二者均被调用,但如果是 then( func1 ).catch( func2 )形式,则在 func1 拒绝时两者均被调用。