Promise
Promise简介
Promise 是一个构造函数,可以封装一个方法,以接收其成功或者失败的值
Promise的作用
Promise支持链式调用,可以解决回调地狱的问题
一个异步函数的不断地去调用 其他异步 函数
链式调用
promise:在promise中启动异步任务 => 任务结束后返回promise对象 => 给返回的promise 对象绑定新的回调函数 (可以在绑定的异步任务结束后绑定多个异步任务)
window.onload = () => {
console.log(11);
document.querySelector('button').addEventListener('click', function () {
function rand(m, n) {
return Math.floor(Math.random() * n + m);
};
let randNum = rand(1, 100);
let p = new Promise((resolve, reject) => {
setTimeout(() => {
if (randNum <= 30) {
resolve(
randNum
);
} else {
reject(
randNum);
};
}, 2000);
});
p.then(
(num) => {
alert('恭喜您,中奖了,中奖数字为' + num)
},
(reson) => {
alert('没中奖,您的数字为' + reson)
}
)
})
}
try-catch语法
try {
定义断言
} catch (err) {
错误 catch 块
} finally () {
}
该语法用来判断程序运行中可能存在的错误,如果有则抛出处理,如果没有,则不会报错
try 定义为 程序测试的代码块
catch 定义为 try 代码块抛出错误接收的代码块
finally 在 try-catch 之后无论是否存在错误都会执行的代码块
一般在 try 代码块内 用 throw 抛出错误,抛出的错误信息将会有 catch 块接收,且仅仅是 第一个 抛出 才会被 catch 接收到
try {
if (1) throw 2;
} catch (err) {
console.log(err);
} finally {
console.log('try-catch 初体验');
}
注意:如果 throw 出现错误且没有 cathc 代码块,则会抛出错误并结束当前代码,后面的代码不再执行
corssorigin
这个属性可以解决部分跨域问题
一般可以使用该属性的有
img,audio,vedio,link,script 标签等
如果这些属性 没有该标签 在访问 跨域资源 的时候,可能会被浏览器限制行为
该属性的值有:
anymous 将请求的跨域模式改为 CORS,凭据模式为 same-origin
use-credentials 将请求的跨域模式设置为 CORS ,凭据模式为 include
PromiseState 状态信息
PromiseState 记录了 promise 对象的当前的状态,
pending 初始化状态
resolve 和 reject 只有能由 pending 改变
要么为 resolved/fullfilled 成功
要么为 rejected 失败
是实例对象中的一个属性
[PromiseState]
不可能由 resolve 转为 reject
也不可能由 reject 转为 resolve
注意:
1.只有 resolve 和 reject 这两种状态。且 一个 promise 只能改变一次
2.promise 对象无论是成功还是失败,总能返回一个结果
3.成功的结果数据一般都是 value ,失败的结果数据 一般都是 reason
PeomiseResult 对象或者失败的结果
PromiseResult 存储的是 Promise 对象成功或者失败的结果
PromiseResult 的值只能由
resolve 函数
reject 函数
参与并修改
Promise.PromiseResult 的值由改变其状态的方法的参数决定,不管是成功还是失败一定会调用一个方法,这个方法一定会传递一个实参,那么这个实参就是 PromiseResult 的值
Promise的工作流程
1. 实例化 promise 对象,并调用传入的回调函数
2.如果回调函数调用返回成功,则将 Pending 改变为 resolved/fullfilded
如果回调函数调用返回失败,则将 pending 改编为 rejected
3.调用 then 方法,传入两个回调函数
4.如果 pending 的状态是 resolved.fullfiled,那么就调用第一个方法,也就是 resolve 回调函数
如果 pending 的状态是 rejected ,则调用第二个方法,也就是 reject 回调函数
Promise 相关的 API
执行器
Promise在被实例化的时候要求传入一个回调函数,回调函数内存在两个子参数回调函数,一个是 resolve,一个是 reject,这个回调函数就是执行器,而两个子构造函数叫做状态修改器
function execute(resolve, reject) {
console.log(11);
};
let p = new Promise(execute);
console.log(22);
then回调函数
Promise.prototype.then((resolveCallBack,rejectCallBack)=>{})
then是定义在 Promise 的原型对象上的函数,这个函数在Promise 实例对象的 Pending 状态发生改变并且返回状态结果后执行,根据 pending 的状态,会执行 resolve 回调或者是 reject 回调,如果成功则执行 resolve 回调,如果失败 则执行 reject 回调
let p = new Promise((resolve, reject) => {
reject('reason');
});
p.then((value) => {
console.log(value);
}, (reason) => {
console.log(reason);
});
console.log(p);
then方法是一个异步函数
catch失败捕捉函数
Promise.prototype.catch(reason)
catch 方法是定义在 Promise 对象上的一个方法,这个方法只能处理 pending 状态为 rejected 的结果
let p = new Promise((resolve, reject) => {
resolve('error');
});
p.catch((reason) => {
console.log(reason);
});
Promise.resolve 方法
let p3 = Promise.resolve(new Promise((resolve, reject) => {
reject(
'reason'
);
}));
p3.catch((err) => {
console.log(err);
})
console.log(
p3);
总结一句话: 定义在 Promise 上的静态成员方法 Promise.resolve 可以快速的得到一个不稳定的 Promise 对象,这个对象的状态由参数决定,如果参数是非失败的 Promise对象,则对应的状态就是 fulfiled ,否则 状态是 rejected ,并且 Promise.PromiseResut 的值为参数值,或者是 rejected 的实参
补充:不管 Promise.resolve 的参数对象是 成功还是失败,结果都是该 参数对象的结果
并且返回的对象就是 参数 Promise 对象
let p1 = new Promise((resolve, reject) => {
resolve('value');
});
let p2 = Promise.resolve(p1);
console.log(p2 === p1);
Promise.reject和Promise.all方法
Promise.reject 是定义在构造函数上的静态方法,这个方法用来创建一个失败的Promise 对象,无论传入什么值,都会返回一个失败的 Promise ,和上面的一样,如果传入的是一个Promise 对象,最后返回的就是 传入的那个Promise 对象
let p1 = Promise.resolve('ok');
let p2 = Promise.reject('err');
let p3 = Promise.resolve('fun');
补充: Promise.reject 方法如果参数是一个 promise 对象,那么返回的结果永远都是该对象,且状态永远都是 rejected
let result = Promise.all([p1, p2,
p3
]);
console.log(result);
console.log(p2);
console.log(result == p2);
可以理解为是 p1 && p2 && p3 的逻辑与
Promise.race 方法
Promise.race 方法和 Promise.all 方向类似,接收的参数都是一个数组,而且都会返回一个Promise对象,但是不同点是Promise.race 方法返回的对象的状态和结果是第一个状态发生改变的 Promise 对象的状态和结果,如果全是异步对象,那么第一个到达消息队列的异步任务的结果的状态和值就是 Promise.race 方法的状态和结果
let p1 = Promise.reject('ok');
let p2 = Promise.reject('err');
let p3 = Promise.resolve('fun');
let result = Promise.race([p1, p2,
p3
]);
console.log(result);
Promise 的几个关键问题
如果改变 Promise 对象的状态
调用 resolve 回调以改变状态为 fulfiled
let p = new Promise((resolve, reject) => {
});
console.log(p);
调用 reject 回调以改变状态为 rejected
let p = new Promise((resolve, reject) => {
});
console.log(p);
throw 抛出错误 以改变状态为 rejected
let p = new Promise((resolve, reject) => {
throw 'err';
});
console.log(p);
Promise的多个回调问题
如果给Promise对象指定了多个回调,只要Promise 对应的状态发生了改变,那么所有指定的回调都会执行
如果状态是 pending ,则不会执行任何回调函数
let p = new Promise((resolve, reject) => {
});
p.then(() => {
console.log(1);
});
p.then(() => {
console.log(2);
});
p.then(() => {
console.log(3);
});
改变Promise状态和回调函数谁先谁后
分两种;
是Promise的状态先改变还是 回调函数先执行
是回调函数先执行还是 Promise的状态先改变
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve(11);
}, 1000)
});
p.then(() => {
console.log(11);
}, () => {
console.log(22);
})
then的返回值
let p = new Promise((resolve, reject) => {
resolve('value');
});
let result = p.then((value) => {
console.log(value);
return new Promise((resolve, reject) => {
reject('reason');
})
}, (reason) => {
console.log(reason);
});
console.log(result);
报错问题
let p = new Promise((resolve, reject) => {
reject('reason');
});
p.then(value => {
console.log(value)
}, reason => {
console.log(reason)
})
let p2 = Promise.reject('err');
console.log(p2);
let p3 = new Promise((resolve, reject) => {
throw 'err';
resolve('value');
});
console.log(p3);
Promise串联多个操作任务
因为 then 也可以返回一个新的Promise对象,那么使用链式调用思想,可以一直串联调用任务
let p = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('我是原Promise');
resolve('value');
}, 1000)
});
let p2 = p.then(value => {
setTimeout(() => {
console.log('我是第一个then的返回值');
return 123;
}, 1000)
});
let p3 = p2.then((value) => {
console.log('我是第二个then的返回值');
});
console.log(p);
console.log(
p2
);
console.log(p3);
Promise的异常穿透
let p = new Promise((resolve, reject) => {
resolve('ok');
});
let p2 = p.then(() => {
console.log(11);
}).then(() => {
console.log(22);
throw 'err'
}).then(() => {
console.log(33);
}).catch(reason => {
console.warn(reason);
return new Promise((resolve, reject) => {
reject('reason');
})
});
console.log(p2);
简而言之:
异常穿透是一种错误处理机制,在链式调用的终点添加 catch 方法或者 then 的错误回调 以捕捉错误,链式调用途中出现任何错误,回直接进入 catch 方法处理,而不会再执行后面的回调函数,错误之前的代码依旧会被正常执行
原因是:
上一个 then 返回的 promise 对象没有处理 错误 ,那么整个的 promise 链都是 失败的 ,而且错误信息会被保留,直到 最后的 错误处理,那么输出的结果 肯定就是 错误信息,和 失败的Promise
注意,如果处理了错误,那么最后返回的Promise的状态就是成功,如果有 return 值,遵循上面的三种状态改变
即:如果返回非 promise 数据,那么就是 fulfiled
如果返回的是 promise 的数据,那么状态和结果由返回的promise 的状态和结果决定
如果在 catch 内抛出错误,那么返回的 Promise 的状态和结果就是 失败
Promise链的中断
let p = new Promise((resolve, reject) => {
resolve('value');
});
p.then(() => {
console.log(11);
})
.then(() => {
console.log(22);
})
.then(() => {
console.log(33);
});