用法与封装
基本用法
//实例化 Promise 对象const p = new Promise(function(resolve, reject){setTimeout(function(){// let data = '数据库中的用户数据';// resolve(data);let err = '数据读取失败';reject(err);}, 1000);});//调用 promise 对象的 then 方法p.then(function(value){console.log(value);}, function(reason){console.error(reason);})
封装 - 提取公用的读取多个文件的方法
//先定义一个含promise的函数let myPromise (path) = {return new Promise((resolve,reject)=>{//读取文件fs.readFile(path,'utf-8',(err,data)=>{if(err) return reject(err)resolve(data)});});};//调用该函数 执行读取文件再.then 执行下一个myPromise('path').then((data) => {console.log(data)return myPromise('path2')}).then((data2) => {console.log(data2)return myPromise('path3')}).cath((err)=>{ //如果有任何一个promise执行失败则返回console.log(err)})
封装 - Ajax
把成功与失败的回调交给外界,不用在onreadystatechange中处理。
// 接口地址: https://api.apiopen.top/getJokeconst p = new Promise((resolve, reject) => {//1. 创建对象const xhr = new XMLHttpRequest();//2. 初始化xhr.open("GET", "https://api.apiopen.top/getJoke");//3. 发送xhr.send();//4. 绑定事件, 处理响应结果xhr.onreadystatechange = function () {//判断if (xhr.readyState === 4) {//判断响应状态码 200-299if (xhr.status >= 200 && xhr.status < 300) {//表示成功resolve(xhr.response);} else {//如果失败reject(xhr.status);}}}})//指定回调p.then(function(value){console.log(value);}, function(reason){console.error(reason);});
简介
Promise 出现的原因
在 Promise 出现以前,我们处理一个异步网络请求,大概是这样:
回调地狱
请求1(function(请求结果1){请求2(function(请求结果2){请求3(function(请求结果3){请求4(function(请求结果4){...})})})})
回调地狱带来的负面作用有以下几点:
- 代码臃肿。
- 可读性差。
- 耦合度过高,可维护性差。
- 代码复用性差。
- 容易滋生 bug。
- 只能在回调里处理异常。
什么是 Promise
Promise 是异步编程的一种解决方案,比传统的异步解决方案【回调函数】和【事件】更合理、更强大。
Promise支持链式调用, 解决回调地狱new Promise(请求1).then(请求2(请求结果1)).then(请求3(请求结果2)).then(请求4(请求结果3)).catch(处理异常(异常信息))
Promise 的状态
实例对象中的一个属性 『PromiseState』
- pending 未决定的
- resolved / fullfilled 成功
- rejected 失败
Promise 对象的值
实例对象中的另一个属性 『PromiseResult』
保存着异步任务『成功/失败』的结果
- resolve
- reject
几个关键问题
改变Promise对象状态
状态只能从pending => fulfilled (resolved)或者pending => rejectedlet p = new Promise((resolve, reject) => {//1. resolve 函数// resolve('ok'); // pending => fulfilled (resolved)//2. reject 函数// reject("error");// pending => rejected//3. 抛出错误// throw '出问题了';});
Promise执行多个回调
可以,每次都可以输出结果。 ```javascript let p = new Promise((resolve, reject) => { resolve(‘OK’); resolve(‘No’); //resolve多次调用无效 });
///指定回调 - 1 p.then(value => { console.log(value); //ok });
//指定回调 - 2 p.then(value => { alert(value); //ok });
<a name="PV3dj"></a>## 回调执行顺序1. 如果没有异步任务,则先resolve,再执行then回调。1. 如果有异步,则先微then后宏settimeout。then先指定回调函数,但不执行里边的回调函数,待resolve |reject执行后才调用```javascript//这是异步情况let p = new Promise((resolve, reject) => {setTimeout(() => {resolve('OK');}, 1000);});p.then(value => {console.log(value);},reason=>{})
中断 Promise 链条
有且只有一个方式将状态改为pendding,因为抛出错误或reject会走catch
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('OK');
}, 1000);
});
p.then(value => {
console.log(111);
// 有且只有一个方式将状态改为pendding
// 因为抛出错误或reject会走catch
return new Promise(() => {});
}).then(value => {
console.log(222);
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason);
});
API
Promise (excutor) {}
Promise 构造函数: Promise (excutor) {}
- executor 函数: 执行器 (resolve, reject) => {}
- resolve 函数: 内部定义成功时我们调用的函数 value => {}
- reject 函数: 内部定义失败时我们调用的函数 reason => {} 说明: executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行
Promise.prototype.then
实例方法,为 Promise 注册回调函数,函数形式:fn(vlaue){},value 是上一个任务的返回结果,then 中的函数一定要 return 一个结果或者一个新的 Promise 对象,才可以让之后的then 回调接收。
为什么promise可以链式调用?设置then方法返回的结果也是promise对象
返回非primise会怎样?如下
返回非primise会对获取回调(.then)产生什么影响? 没影响 依然是一个promise对象
//创建 promise 对象
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('用户数据');
// reject('出错啦');
}, 1000)
});
//调用 then 方法 then方法的返回结果是 Promise 对象, 对象状态由回调函数的执行结果决定
//1. 如果回调函数中返回的结果是 非 promise 类型的属性, 状态为成功, 返回值为对象的成功的值
const result = p.then(value => {
console.log(value);
//1. 非 promise 类型的属性
// return 'iloveyou';
//控制台输出的结果 状态为成功, 返回值为对象的成功的值
//[[PromiseState]]: "fulfilled"
//[[PromiseResult]]: "iloveyou"
//2. 是 promise 对象
// return new Promise((resolve, reject)=>{
// // resolve('ok');
// reject('error');
// });
//控制台输出的结果 状态为成功
//[[PromiseState]]: "fulfilled"
//[[PromiseResult]]: "ok"
//3. 抛出错误
// throw new Error('出错啦!');
throw '出错啦!';
//控制台输出的结果 状态为失败
//[[PromiseState]]: "rejected"
//[[PromiseResult]]: "出错啦!"
}, reason=>{
console.warn(reason);
});
console.log(result)
Promise.resolve
类方法,.then的第一个参数, 异步操作成功后调用, 返回的 promise 对象的状态为 resolved 。
let p1 = Promise.resolve(521);
//如果传入的参数为 非Promise类型的对象, 则返回的结果为成功promise对象
//如果传入的参数为 Promise 对象, 则参数的结果决定了 resolve 的结果
let p2 = Promise.resolve(new Promise((resolve, reject) => {
// resolve('OK');
reject('Error');
}));
// console.log(p2);
p2.catch(reason => {
console.log(reason);
})
Promise.reject
类方法,.then的第二个参数, 异步操作失败后调用, 且与 resolve 唯一的不同是,返回的 promise 对象的状态为 rejected。(结果永远是失败的 , 内容由传入值决定 即时传入一个成功的promise)
// let p2 = Promise.reject('iloveyou');
let p3 = Promise.reject(new Promise((resolve, reject) => {
resolve('OK');
}));
console.log(p3);
Promise.prototype.catch
实例方法,捕获异常,函数形式:fn(err){}, err 是 catch 注册 之前的回调抛出的异常信息。
Promise()
.then(function(data){
console.log(data)
})
.then(function(data){
console.log(data)
})
.cath(function(reason){ //捕获异常
console.log(reason)
})
Promise.all
类方法,多个 Promise 任务同时执行。 如果全部成功执行,则以数组的方式返回所有 Promise 任务的执行结果。 如果有一个 Promise 任务 rejected,则只返回 rejected 任务的结果。 必须所有操作都成功,否则报错
Promise
.all([run1(),run2(),run3()])
.then(function(data){
console.log(data)
})
Promise.allSettled
无论成功与否都会返回对应数据
//声明两个promise对象
const p1 = new Promise((resolve, reject)=>{
setTimeout(()=>{
resolve('商品数据 - 1');
},1000)
});
const p2 = new Promise((resolve, reject)=>{
setTimeout(()=>{
// resolve('商品数据 - 2');
reject('出错啦!');
},1000)
});
//调用 allsettled 方法
const result = Promise.allSettled([p1, p2]);
console.log(result);
Promise.race
类方法,多个 Promise 任务同时执行,返回最先执行结束(谁跑得快以谁的 Promise 任务的结果为准) ,不管这个 Promise 结果是成功还是失败。
Promise
.race([run1(),run2(),run3()])
.then(function(data){
console.log("我执行得最慢",data)
})
resolve深度解析
两种方式创建, 这两种方式都会返回一个 Promise 对象。
- 1、new Promise(fn)
- 2、Promise.resolve(fn)
Promise 的常用 API 如下:
- Promise.resolve(value) 看例子解析
类方法,该方法返回一个以 value 值解析后的 Promise 对象 1、如果这个值是个 thenable(即带有 then 方法),返回的 Promise 对象会“跟随”这个 thenable 的对象,采用它的最终状态(指 resolved/rejected/pending/settled) 2、如果传入的 value 本身就是 Promise 对象,则该对象作为 Promise.resolve 方法的返回值返回。 3、其他情况以该值为成功状态返回一个 Promise 对象。
上面是 resolve 方法的解释,传入不同类型的 value 值,返回结果也有区别。这个 API 比较重要,建议大家通过练习一些小例子,并且配合上面的解释来熟悉它。如下几个小例子:
//如果传入的 value 本身就是 Promise 对象,则该对象作为 Promise.resolve 方法的返回值返回。
function fn(resolve){
setTimeout(function(){
resolve(123);
},3000);
}
let p0 = new Promise(fn);
let p1 = Promise.resolve(p0);
// 返回为true,返回的 Promise 即是 入参的 Promise 对象。
console.log(p0 === p1);
//解析
//第7行相当于以下代码。此时p0就是promise对象
//第8 如果传入的 value 本身就是 Promise 对象,则该对象作为 Promise.resolve 方法的返回值返回。
let p0 = new Promise(function(){
setTimeout(function(){
resolve(123);
},3000);
});
传入 thenable 对象,返回 Promise 对象跟随 thenable 对象的最终状态。
ES6 Promises 里提到了 Thenable 这个概念,简单来说它就是一个非常类似 Promise 的东西。最简单的例子就是 jQuery.ajax,它的返回值就是 thenable 对象。但是要谨记,并不是只要实现了 then 方法就一定能作为 Promise 对象来使用。
//如果传入的 value 本身就是 thenable 对象,返回的 promise 对象会跟随 thenable 对象的状态。
let promise = Promise.resolve($.ajax('/test/test.json'));// => promise对象
promise.then(function(value){
console.log(value);
});
返回一个状态已变成 resolved 的 Promise 对象。
let p1 = Promise.resolve(123);
//打印p1 可以看到p1是一个状态置为resolved的Promise对象
console.log(p1)
