JavaScript-Promise总结!

前言:

​ 最近在做项目对接后端接口时,遇到了一个bug,和promise有关,于是在网上找资料,找啊找,发现自己对Promise的了解还是很生疏的,于是就开始了对promise的学习,刚好最近也想开始写一些文章来记录自己的学习路程,也希望可以帮助到大家。然后,就开始了我前端之路的第一篇知识输出文章,请大家多多指教!

正文:

Promise概述

​ 异步编程是JavaScript一大特点,建议大家先了解一下JavaScript的异步编程实现,这里推荐一篇文章—JavaScript异步编程 - 熊建刚的文章 - 知乎 https://zhuanlan.zhihu.com/p/26567159

​ Promise是实现异步编程的一种解决方案,比传统的的解决方案(回调函数和事件)更加先进,先进在哪里呢?上代码!

//传统异步编程方式
setTimeout(function(){
console.log("doThing1");
setTimeout(function(){
console.log("doThing2");
setTimeout(function(){
console.log("doThing3");
setTimeout(function(){
console.log("doThing4");
},1000)
},1000)
},1000)
},1000)

//promise实现
let p1=new Promise((resolve,reject)=>{
setTimeout(function () {
console.log("doThing1");
resolve();
}, 1000);
})
let p2=new Promise((resolve,reject)=>{
setTimeout(function () {
console.log("doThing1");
resolve();
}, 1000);
})v
let p3=new Promise((resolve,reject)=>{
setTimeout(function () {
console.log("doThing1");
resolve();
}, 1000);
})
let p4=new Promise((resolve,reject)=>{
setTimeout(function () {
console.log("doThing1");
resolve();
}, 1000v);
})
p1.then(p2).then(p3).then(p4);

上面的代码,我们想按照顺序去做4件事情,如果按照传统的方式来实现很容易造成“函数瀑布”,这样的代码被称为“回调地狱”,看起来就很头疼,像promise这样实现更为直观,维护起来也方便很多,这仅仅是代码书写上的优势,在一些错误处理,顺序性等等都比传统异步编程更为优化,这里就不做深究了。

​ “Promise 对象代表了未来将要发生的事件,用来传递异步操作的消息”。一个 Promise对象会将异步操作的最终结果和结果的处理程序关联起来(成功or失败),那么自然就要求promise需要有状态,我们才可以知道promise现在是成功了还是失败了。

promise的状态:

  1. pending(等待),初始状态,未知操作成功还是失败
  2. fulfilled(已完成),最终状态,操作成功,可以调用成功处理程序
  3. rejected(已失败),最终状态,操作失败,可以调用失败处理程序

这里引入一个例子:小明的妈妈在做家务没空买菜,那么她叫小明去买菜,这个任务就是一个promise,好,小明去买菜了,小明买菜这个过程是一个异步操作,那么小明买菜的结果是什么呢?这就是说这个命令有没有完成?有两种情况,第一种是小明成功买到菜了,接下来小明妈妈就是做饭啦,第二种情况,小明把钱拿去打游戏了没买到菜,接下来小明妈妈就是把他打一顿啦….

接下来讲promise的使用都会用到这个例子。

promise的方法

Promise()-promise的构造函数

作用:

创建一个新的 Promise 对象。该构造函数主要用于包装还没有添加 promise 支持的函数。

Promise接受函数两个参数(resolve, reject),当异步任务成功时,调用第一个参数resolve,将promise对象的状态设为fulfilled,并返回成功值;失败时将调用第二个参数reject将promise对象的状态设为rejected,并返回失败原因;

使用:
let order=new Promise((resolve,reject)=>{
setTimeout(()=>{
//小明买菜ing
// (1)小明一路破关斩将,抵御各种诱惑,成功买到一条鱼和一斤牛肉
//(2)小明看到菜市场旁边的游戏厅,被里面的游戏所吸引,把钱全花在打游戏那里了,没有买到菜

//小明回到家告诉妈妈
resolve("我买到菜了!买了一条鱼和一斤牛肉")
//reject("我没有买到菜,钱全花在打游戏了......") //敢作敢当....

},1000)//这里用setTimeout来模拟小明去买菜这个异步任务
})

注意!promise的状态一经决定,无法改变,所以当用了resolve再用reject时reject不起效果,promise状态仍是fulfilled

Promise.prototype.then()

作用:

这个方法可以获取promise的状态,并进行结果处理。

它最多需要有两个参数:Promise 的成功和失败情况的回调函数。

语法:
promise.then(value => {
// fulfillment
}, reason => {
// rejection
});
使用:
let order=new Promise((resolve,reject)=>{
setTimeout(()=>{
//小明买菜ing
// (1)小明一路破关斩将,抵御各种诱惑,成功买到一条鱼和一斤牛肉
//(2)小明看到菜市场旁边的游戏厅,被里面的游戏所吸引,把钱全花在打游戏那里了,没有买到菜

//小明回到家告诉妈妈
resolve("我买到菜了!买了一条鱼和一斤牛肉")
//reject("我没有买到菜,钱全花在打游戏了......") //敢作敢当....
},1000)//这里用setTimeout来模拟小明去买菜这个异步任务
})
order.then((res)=>{
console.log(res);
console.log("妈妈夸了一顿小明,并做了红烧鱼和爆炒牛肉");
},(err)=>{
console.log(err);
console.log("妈妈打了一顿小明,并决定今晚出去吃"); //好像小明这样做确实不错,可以出去吃了
})
//输出结果:
我买到菜了!买了一条鱼和一斤牛肉
妈妈夸了一顿小明,并做了红烧鱼和爆炒牛肉

//如果是reject("我没有买到菜,钱全花在打游戏了......")
我没有买到菜,钱全花在打游戏了......
妈妈打了一顿小明,并决定今晚出去吃
tips:

由于 then 和 Promise.prototype.catch()方法的返回值都是 promise,它们可以被链式调用——这同时也是一种被称为复合composition) 的操作。

//类似  p1.then(p2).then(p3).then(p4).catch(p5).then(p6).......

Promise.prototype.catch()

作用:

​ 这个方法主要获取promise错误状态,并进行结果处理。其实和promise.then(undefined,onRejected)时一样的,不过promise.then优先(等下会有示例)。

语法:
promise.catch(function(reason) {
// 拒绝z
});
使用:
let order=new Promise((resolve,reject)=>{
setTimeout(()=>{
//小明买菜ing
// (1)小明一路破关斩将,抵御各种诱惑,成功买到一条鱼和一斤牛肉
//(2)小明看到菜市场旁边的游戏厅,被里面的游戏所吸引,把钱全花在打游戏那里了,没有买到菜

//小明回到家告诉妈妈
// resolve("我买到菜了!买了一条鱼和一斤牛肉")
reject("我没有买到菜,钱全花在打游戏了......") //敢作敢当....
},1000)//这里用setTimeout来模拟小明去买菜这个异步任务
})

order.catch(err=>{
console.log("catch err: "+err);
console.log("妈妈打了一顿小明,并决定今晚出去吃");
})
//输出结果:
catch err: 我没有买到菜,钱全花在打游戏了......
妈妈打了一顿小明,并决定今晚出去吃
tips:
  1. 当和promise.then(undefined,onRejected)同时存在时,onRejected优先
//构造Promise order同上
order.then(undefined,err=>{
console.log("then err: "+err);
})
.catch(err=>{
console.log("catch err: "+err);
})
//输出结果:
then err: 我没有买到菜,钱全花在打游戏了......
  1. catch可以捕获then()里面的函数
order.then(undefined,err=>{
console.log("then err: "+err);
throw Error("then出错了")
})
.catch(err=>{
console.log("catch err: "+err);
})
//输出结果
then err: 我没有买到菜,钱全花在打游戏了......
catch err: Error: then出错了

3.当在链式调用时,catch可以捕获前面任意一个then中的错误,这也就是说我们写代码的时候最好可以用上catch

//类似  p1.then(p2).then(p3).then(p4).then(p5).catch(err).......
//catch可以捕获p2 p3 p4 p5中任意一个中的错误

Promise.prototype.finally()

作用:

当promise结束是,无论最终状态如何,fulfilled还是rejected,都会执行指定回调函数

语法:
promise.finally(function() {
// 返回状态为(resolved 或 rejected)
});
使用:
let order=new Promise((resolve,reject)=>{
setTimeout(()=>{
//小明买菜ing
// (1)小明一路破关斩将,抵御各种诱惑,成功买到一条鱼和一斤牛肉
//(2)小明看到菜市场旁边的游戏厅,被里面的游戏所吸引,把钱全花在打游戏那里了,没有买到菜

//小明回到家告诉妈妈
// resolve("我买到菜了!买了一条鱼和一斤牛肉")
reject("我没有买到菜,钱全花在打游戏了......") //敢作敢当....

//promise的状态一经决定,无法改变,所以当用了resolve再用reject时reject不起效果,promise状态仍是fulfilled
},1000)//这里用setTimeout来模拟小明去买菜这个异步任务
})

order.then((res)=>{
console.log(res);
console.log("妈妈夸了一顿小明,并做了红烧鱼和爆炒牛肉");
},(err)=>{
console.log(err);
console.log("妈妈打了一顿小明,并决定今晚出去吃"); //好像小明这样做确实不错,可以出去吃了
}).catch((err)=>{
//获取前面出现的错误,有可能妈妈做饭的时候鱼被猫吃了.......
}).finally(()=>{
console.log("无论结果如何,最终都是要吃饭的!事已至此,先吃饭吧。。。。");
})

//输出结果
我没有买到菜,钱全花在打游戏了......
妈妈打了一顿小明,并决定今晚出去吃
无论结果如何,最终都是要吃饭的!事已至此,先吃饭吧。。。。

Promise.resolve()

作用:

返回一个带有成功参数的Promise对象。注意此时的promise对象已是fulfilled的最终状态。

参数:
  1. 如果参数是一个值,将把这个值作为返回的promise的成功参数

  2. 如果这个值是一个 promise ,那么将返回这个 promise

  3. 如果是一个thenable,返回的promise会“跟随”这个thenable的对象,采用它的最终状态。

    thenable:

    thenable是任何含有then()方法的对象或函数,作用使promise的实现更具有通用性

    类似:

    let thenable = {
    then: (resolve, reject) => {
    resolve(thenable)
    }
    }

    判断一个对象是不是thenable,用到类型检查,也称为鸭式辩型

    if(p!=null&&(typeof p==="object"||typeof p==="function")&&(typeof p.then==="function")){
    //p是一个thenable
    }else{
    //p不是一个thenable
    }
示例:
let thenable = {
then: (resolve, reject) => {
resolve("thenble最终状态")
}
}

let promise=Promise.resolve(thenable)

promise.then((res)=>{
console.log(res)
},err=>{
//用不上
}
)
//打印结果
//thenble最终状态


let promise1 = Promise.resolve(11111);

let promise=Promise.resolve(promise1)

promise.then((res)=>{
console.log(res)
},err=>{
//用不上
}
)
//打印结果
//11111


let promise=Promise.resolve(2222)

promise.then((res)=>{
console.log(res)
},err=>{
//用不上
}
)
//打印结果
//22222

Promise.reject()

作用:

​ 返回一个带有拒绝原因的Promise对象。注意此时的promise对象已是rejected的最终状态

Promise.resolve()的区别

Promise.reject 方法的参数,会原封不动地作为 reject 的参数,变成后续方法的参数。这一点与 Promise.resolve 方法不一致。

  //Promise.resolve() 和Promise.reject()的区别    
const thenable ={
then(resolve, reject){
// resolve("成功了")
reject('出错了');
}
};


//Promise.resolve() 和Promise.reject()的区别
//Promise.resolve(thenable)
Promise.reject(thenable)
.then(res=>{
console.log("then res: "+res)
console.log(res===thenable)
})
.catch(err =>{
console.log("catch err: "+err)
console.log(err===thenable)
})
//打印结果
catch err: [object Object]
true

//当执行Promise.resolve(thenable)
catch err: 出错了
false

对resolve(thenable)结果解析:

  1. 当thnable传入resolve时,将立即执行thnable的then方法,resolve返回它的最终状态reject(‘出错了’),此时resolve返回的promise参数并不是一个thnable了,而是“出错了”

  2. 而当thnable传入rejected时,并不会执行thnable的then方,而是原封不动将thnable作为resolve返回的promise参数

Promise.all()

作用:

整合多个promise示例,返回最终一个promise实例

参数:

一个promise的iterable(注:Array,Map,Set都属于ES6的iterable类型)

返回值:

  1. Promise的resolve回调执行是在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的时候
  2. 只要任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出的错误信息。
  3. 个人觉得有点像与操作了,当所有promise都fulfilled时,返回的promise才是fulfilled,完成状态的结果都是一个数组,它包含所有的传入迭代参数对象的值(也包括非 promise 值);而当任意一个promise失败时,返回的promise时rejected,Promise.all()异步地将失败的那个结果给失败状态的回调函数,而不管其它 promise 是否完成。
let promise1=Promise.resolve("小明成功买到菜了");
let promise2=Promise.reject("小明没晾衣服");
let promise3=Promise.resolve("小明刷完高数了");

Promise.all([promise1, promise2, promise3]).then(res => {
console.log(res);
});
//打印结果
[ '小明成功买到菜了', '小明晾衣服了', '小明刷完高数了' ]


let promise1=Promise.resolve("小明成功买到菜了");
let promise2=Promise.reject("小明没晾衣服");
let promise3=Promise.resolve("小明刷完高数了");

let promise=Promise.all([promise1, promise2, promise3]);
setTimeout(()=>{
console.log(promise)
},0)
//打印结果
Promise { <rejected> '小明没晾衣服' }


至于第二个例子我为什么要用setTimeout,大家可以保留疑问,假如直接打印,结果会是Promise { <pending> },这就涉及到Promise的异步处理,文章后我会讲解

Promise.allSettled()

作用:

​ 方法返回一个在所有给定的promise都已经fulfilledrejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果。

​ 如果有多个彼此不依赖的异步任务完成时,然后你要知道所有promise的结果,又不想一个一个地获取时,可以用到这个。相反,假如你的异步任务有依赖则要用Promise.all()

参数:

​ 和Promise.all()一致

示例:
let promise1=Promise.resolve("小明成功买到菜了");
let promise2=Promise.reject("小明没晾衣服");
let promise3=Promise.resolve("小明刷完高数了");

Promise.allSettled([promise1, promise2, promise3]).then((result)=>{
result.forEach((item)=>{
console.log(item)
})
})
//打印结果
[
{ status: 'fulfilled', value: '小明成功买到菜了' },
{ status: 'rejected', reason: '小明没晾衣服' },
{ status: 'fulfilled', value: '小明刷完高数了' }
]

Promise.race()

作用:

返回一个 promise,一旦迭代器中的某个promise解决或拒绝,返回的 promise就会解决或拒绝。

race-比赛,看哪个promise最先被定义最终状态,则返回该结果

参数:

​ 和Promise.all()一致

示例:
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, '小明做完作业了'); //小明做完作业花费了500ms
});

const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, '小东做完作业了'); //小东做完作业花费了100ms
});

let promise=Promise.race([promise1, promise2]);
setTimeout(()=>{
console.log(promise)
},1000);

//打印结果
Promise { '小东做完作业了' }



const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, '小明做完作业了'); //小明做完作业花费了500ms
});

const promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, '小东不想作业了'); //小东100ms后就说不做作业了...
});

let promise=Promise.race([promise1, promise2]);
setTimeout(()=>{
console.log(promise)
},1000);
//打印结果
Promise { <rejected> '小东不想作业了' }

Promise.any()

作用:

Promise.all()相反,及相当于做或操作,只要有一个promise成功了,那么最终结果就成功(只返回第一个成功的promise),如果都不成功,最终promise才为rejected。

参数:

​ 和Promise.all()一致

示例:
let promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, '小明做完作业了'); //小明做完作业花费了500ms
});

let promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, '小东不想作业了'); //小东100ms后就说不做作业了...
});
let promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, '小李做完作业了'); //小明做完作业花费了500ms
});
Promise.any([promise1, promise2,promise3]).then(res=>{
console.log(res)
})
//打印结果
"小李做完作业了"


let promise1 = new Promise((resolve, reject) => {
setTimeout(reject, 500, '小明不想作业了'); //小明500ms后就说不做作业了...
});

let promise2 = new Promise((resolve, reject) => {
setTimeout(reject, 100, '小东不想作业了'); //小东100ms后就说不做作业了...
});
let promise3 = new Promise((resolve, reject) => {
setTimeout(reject, 200, '小李不想作业了'); //小明100ms后就说不做作业了...
});
Promise.any([promise1, promise2,promise3]).catch(err=>{
console.log(err.message)})
//打印结果
"All promises were rejected"

Promise的异步执行

我们先来看一段代码!

let promise1 = Promise.resolve(11111);

let promise2 = promise1.then(value => {
console.log("promise1的value: " + value);
return value;
});

console.log(promise2);

setTimeout(() => {
console.log(promise2);
});
//打印结果:
Promise { <pending> }
promise1的value: 11111
Promise { 11111 }

是不是和你的预期不一样,这就是Promise的异步执行;

我们来分析一下:

​ 其实代码执行到 let promise1 = Promise.resolve(11111); Promise.resolve不会在时不会立即执行的,这是交给异步来完成的,那么就顺着执行下面的代码了.

​ 到let promise2 = promise1.then时,此时的promise1的状态还是pending,所以promise2也是pending,此时value是undefined的。

​ 然后就是执行console.log(promise2),所以打印的第一个是Promise { <pending> },之后再setTimeout,此时promise1 promise2才是操作完成的,value是111。

这也是和JavaScript的异步编程有关!

Promise的缺点

  1. 一旦新建Promise,它就会立即执行,无法中途取消。
  2. 如果不设置回调函数,Promise 内部抛出的错误,不会反应到外部。
  3. 当处于 pending 状态时,无法得知目前进展到哪一个阶段(刚开始还是即将完成)。

总结

​ 终于写完了,自己也系统地学完了Promise,输出亦是一种学习的过程。

​ 这篇文章主要是对Promise的理解和使用,至于Promise的实现,我也只是简单的看了大概,大家有兴趣可以继续深究源码。

​ 此文章只代表个人见解,站在巨人的肩膀上看问题,感谢前辈们的贡献,如有错误,请指出!感谢大家!

源码实现

const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';

const resolvePromise = (promise2, x, resolve, reject) => {
// 自己等待自己完成是错误的实现,用一个类型错误,结束掉 promise Promise/A+ 2.3.1
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
// Promise/A+ 2.3.3.3.3 只能调用一次
let called;
// 后续的条件要严格判断 保证代码能和别的库一起使用
if ((typeof x === 'object' && x != null) || typeof x === 'function') {
try {
// 为了判断 resolve 过的就不用再 reject 了(比如 reject 和 resolve 同时调用的时候) Promise/A+ 2.3.3.1
let then = x.then;
if (typeof then === 'function') {
// 不要写成 x.then,直接 then.call 就可以了 因为 x.then 会再次取值,Object.defineProperty Promise/A+ 2.3.3.3
then.call(x, y => { // 根据 promise 的状态决定是成功还是失败
if (called) return;
called = true;
// 递归解析的过程(因为可能 promise 中还有 promise) Promise/A+ 2.3.3.3.1
resolvePromise(promise2, y, resolve, reject);
}, r => {
// 只要失败就失败 Promise/A+ 2.3.3.3.2
if (called) return;
called = true;
reject(r);
});
} else {
// 如果 x.then 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.3.4
resolve(x);
}
} catch (e) {
// Promise/A+ 2.3.3.2
if (called) return;
called = true;
reject(e)
}
} else {
// 如果 x 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.4
resolve(x)
}
}

class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks= [];

let resolve = (value) => {
// 如果 value 是一个promise,那我们的库中应该也要实现一个递归解析
if(value instanceof Promise){
// 递归解析
return value.then(resolve,reject)
}
if(this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
this.onResolvedCallbacks.forEach(fn=>fn());
}
}

let reject = (reason) => {
// 如果 value 是一个promise,那我们的库中应该也要实现一个递归解析
if(reason instanceof Promise){
// 递归解析
return reason.then(resolve,reject)
}
if(this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach(fn=>fn());
}
}

try {
executor(resolve,reject)
} catch (error) {
reject(error)
}
}

then(onFulfilled, onRejected) {
//解决 onFufilled,onRejected 没有传值的问题
//Promise/A+ 2.2.1 / Promise/A+ 2.2.5 / Promise/A+ 2.2.7.3 / Promise/A+ 2.2.7.4
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
//因为错误的值要让后面访问到,所以这里也要跑出个错误,不然会在之后 then 的 resolve 中捕获
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
// 每次调用 then 都返回一个新的 promise Promise/A+ 2.2.7
let promise2 = new Promise((resolve, reject) => {
if (this.status === FULFILLED) {
//Promise/A+ 2.2.2
//Promise/A+ 2.2.4 --- setTimeout
setTimeout(() => {
try {
//Promise/A+ 2.2.7.1
let x = onFulfilled(this.value);
// x可能是一个proimise
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
//Promise/A+ 2.2.7.2
reject(e)
}
}, 0);
}

if (this.status === REJECTED) {
//Promise/A+ 2.2.3
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0);
}

if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e)
}
}, 0);
});

this.onRejectedCallbacks.push(()=> {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject)
} catch (e) {
reject(e)
}
}, 0);
});
}
});

return promise2;
}
}


static resolve(data){
return new Promise((resolve,reject)=>{
resolve(data);
})
}


static reject(reason){
return new Promise((resolve,reject)=>{
reject(reason);
})
}

Promise.prototype.catch = function(errCallback){
return this.then(null,errCallback)
}

Promise.prototype.finally = function(callback) {
return this.then((value)=>{
return Promise.resolve(callback()).then(()=>value)
},(reason)=>{
return Promise.resolve(callback()).then(()=>{throw reason})
})
}


Promise.all = function(values) {
if (!Array.isArray(values)) {
const type = typeof values;
return new TypeError(`TypeError: ${type} ${values} is not iterable`)
}
return new Promise((resolve, reject) => {
let resultArr = [];
let orderIndex = 0;
const processResultByKey = (value, index) => {
resultArr[index] = value;
if (++orderIndex === values.length) {
resolve(resultArr)
}
}
for (let i = 0; i < values.length; i++) {
let value = values[i];
if (value && typeof value.then === 'function') {
value.then((value) => {
processResultByKey(value, i);
}, reject);
} else {
processResultByKey(value, i);
}
}
});
}



Promise.race = function(promises) {
return new Promise((resolve, reject) => {
// 一起执行就是for循环
for (let i = 0; i < promises.length; i++) {
let val = promises[i];
if (val && typeof val.then === 'function') {
val.then(resolve, reject);
} else { // 普通值
resolve(val)
}
}
});
}


//借助race封装promise,实现随时暂停
function wrap(promise) {
// 在这里包装一个 promise,可以控制原来的promise是成功还是失败
let abort;
let newPromise = new Promise((resolve, reject) => { // defer 方法
abort = reject;
});
let p = Promise.race([promise, newPromise]); // 任何一个先成功或者失败 就可以获取到结果
p.abort = abort;
return p;
}

const promise = new Promise((resolve, reject) => {
setTimeout(() => { // 模拟的接口调用 ajax 肯定有超时设置
resolve('成功');
}, 1000);
});

let newPromise = wrap(promise);

setTimeout(() => {
// 超过3秒 就算超时 应该让 proimise 走到失败态
newPromise.abort('超时了');
}, 3000);

newPromise.then((data => {
console.log('成功的结果' + data)
})).catch(e => {
console.log('失败的结果' + e)
})