作用
- 解决回调地狱,将异步操作以同步的操作的流程表达出来,避免了层层嵌套的回调函数
优点
- 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套回调函数
- Promise对象提供统一接口,使得控制异步操作更加容易
缺点
- 无法取消promise,一旦新建立就会立即执行,无法中途取消
- 如果不设置回调函数,promise内部抛出的错误,不会反应到外部
- 当处于pending状态时,无法得知目前进展到哪一个阶段(刚开始还是刚结束)
Promise.prototype.then
then()方法返回一个Promise,他最多需要两个参数:Promise的成功和失败情况的回调函数
【注意】:如果忽略针对某个状态的回调函数参数,或者提供非函数参数,那么then方法将会丢失关于该状态的回调函数,但是并不会产生错误,如果调用then的promise的状态(fulliment,rejection)发生改变,但是then中并没有关于这种状态的回调函数,那么then将会创建一个没有经过回调函数处理的新的promise对象,这个新的promise只是简单的接收调用这个then的原promise的终态作为它的终态
p.then(onFulfilled[,onReject]);
p.then(value=>{},reason=>{})
onFulfilled
当promise变成接收状态(fulfilled)时调用的函数,该函数有一个参数,即接受的最终结果,如果该参数不是函数,则会在内部被替换为(x)=>x,即原样放回promise最终结果的函数
onReject
当promise变成拒绝状态(rejected)时调用的函数,该函数有一个参数,即拒绝的原因,如果该参数不是函数,则会在内部替换一个thrower函数
返回值
当一个promise完成或失败时,返回函数将被异步调用(由当前的线程来调度完成),具体的返回值依据以下规则返回,如果then中的回调函数
- 返回一个值,那么then返回的promise将会成为接受状态,并且将返回值作为接受状态的回调函数的参数值
- 没有返回任何值,那么then返回的promise将会成为接受状态,并且该接受状态的回调函数的参数值为undefined
- 抛出一个错误,那么then返回的promise将会成为promise将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值
- 返回一个已经时接受状态的promise,那么then返回的promise也会成为接受状态,并且将那个promise的接受状态的回调函数的参作为被返回的promise的接受状态回调函数的参数值
- 返回一个已经是拒绝状态的promise,那么then返回的promise也会成为拒绝状态,并且将那个promise的拒绝状态的回调函数的参数值作为该返回的promise的拒绝状态回调函数的参数值
- 返回一个未定状态的promise,那么then返回promise的状态也是未定的,并且它的终态与那个promise的终态相同,同时,它变为终态时调用的回调函数参数与那个promise变为终态时的回调函数的参数是相同的
Promise.reject(7).then(
()=>console.log(1),
undefined
).then(
()=>console.log(2),
(err)=>console.log(err,3)
)
//7 3
//第一个promise是reject状态,应该执行then中的第二个回调,但是第二个参数为undefined,不是一个函数,(promsie内部会判断这个回调是不是一个函数,如果是直接执行,如果不是会封装一个简易的h)所以promise内部会封装一个简易的函数来抛出错误,所以这个then返回的也是一个reject的promise
Promise.prototype.catch
catch方法返回一个promise,并且处理拒绝的情况,它的行为与调用promise.prototype.then相同
语法
p.catch(onRejected);
p.catch(function (reason){})
Promise.prototype.finally
finnaly方法返回一个promise,在promise结束时,无论结果是fulfilled或者rejected,都会执行指定的回调函数,这为在promise是否成功完成后都需要执行的代码提供了一种方式,这避免了同样的语句需要在then和catch中各写一次的情况
参数
onFinally
promise结束后调用Function
返回值
返回一个设置了finnally回调函数的promise对象
描述
如果你想在promise执行完毕后无论其结果怎么样都做一些处理或清理时,finally方法可以使用
【与then,catch不同】
- 调用内联函数时,不需要多次声明该函数或为函数创建一个变量来保存它
- 由于无法知道promise的最终状态,所以finally的回调函数中不接受任何参数,它仅用于无论最终结果如何都要执行的情况
- 与
promise.resolve(2).then(()=>{},()={})(resolve的结果为undefined)不同,Promise.resolve(2).finally(()=>{})resolved的结果为2 promise.reject(()=>{},()=>{})(rejected的结果为undefined),promsie.reject(3).finally(()=>{})的结果为3
Promise.all
Promise.all()方法接收一个promise类型的输入(Array,Map,Set等都属于ES6的iterable类型)的输入,并且只返回一个promise实例,那个输入的所有的promise的resolve回调的结果是一个数组,这个promise的resolve回调执行只在所有输入的promise的resolve回调都结束,或者输入的iterable里没有promise了的是时候,只要是任何一个输入的promise的reject回调执行或者输入不合法的promise就会立即抛出错误,并且reject的是第一个抛出错误的信息
返回值
- 如果传入的参数是一个空的可迭代对象,则返回一个已完成状态的promise
- 如果传入的参数不包含任何promise,则返回一个异步完成的promise
- 其他情况下返回一个处理中(pending)的promsie,这个返回的promise之后会在所有的promise都完成或有一个promise失败时异步地变为完成或失败,返回值将会按照参数内的promsie顺序排列,而不是由调用promise的完成顺序决定
var resolvedPromisesArray = [Promise.resolve(33), Promise.resolve(44)];
//promsie { <pending> }
//the stack is empty
//promise { [3] }
var resolvedPromisesArray = [33,22];
//Promise { <pending> }
//the stack is empty
//promise { [33,22] }
var resolvedPromisesArray = [];
//Promise { [] }
//the stack is empty
//promise { [] }
var p = Promise.all(resolvedPromisesArray);
console.log(p);
setTimeout(function () {
console.log('the stack is now empty');
console.log(p);
);
Promise.race
Promise.race(iterable)方法返回一个promise,一旦迭代器中的某个promise解决或拒绝,返回的promise就会解决或拒绝
返回值
一个待定的promise只要给定迭代中的一个promise解决或拒绝,就次啊用第一个promise的值作为它的值,从而异步的解析或拒绝
描述
race函数返回一个promise,它将与第一个传递的promise相同的完成方式被完成,它可以是完成也可以是失败,这就要取决于第一个完成的方式是两个中的那个
如果可迭代是空的,则返回promise将永远等待
如果迭代包含一个或多个非承诺值和/或已解决/拒绝的承诺,则promise.race将解析为迭代中找到的第一个值
Promise.resolve
promise.resolve(value)方法返回一个以给定值解析后的promise对象,如果这个值是一个promise,那么将返回这个promise,如果这个是是thenable(即带有then方法),返回的promise会跟随这个thenable的对象,采用它的最终状态,否则返回的promise将以此值完成,函数将这类promise的对象的多层嵌套展平
【注意:不要在解析为自身的thenable上调用promise.resolve,这将导致无限递归,应为它视图展平无限嵌套的promise】
let thenable={
then:(resolve,reject)=>{
resolve(thenable);
}
}
Promise.resolve(thenable);//这会造成一个死循环
参数
将被promise对象解析的参数,也可以是一个promise对象,或者是一个thenable
返回值
返回一个带着给定值解析过的promise对象,如果参数本身就是一个promise对象,则直接返回这个promise对象
var original=Promise.resolve(33);
var cast=Promise.resolve(original);
cast.then((value)=>{
console.log(value);
})
console.log('original===cast?'+(original)===cast)
//orignal === casr ?true
//value:33
Promise.reject
promise.reject返回一个带有拒绝原因的promise
promise.allSettled
promise.allSettled方法返回一个在所有给定的promie都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的promise结果,当由多个彼此不依赖的异步任务成功完成时,或者总是想知道每个promise的结果时,通常使用它
参数
一个可迭代对象
返回值
一旦所指定的promise集合中每一个promise已经完成,无论时成功的达成或拒绝,为决议的promise都将被异步完成,即使,所返回的promise的处理器将传入一个数组作为输入,该数组包含原始promise集中每个promise的结果
对于每个结果对象,都有一个status字符串,如果它的值为fulfilled,则结果对象上存在一个value,如果值为reject,value(或reason)反映了每个promise决议(或拒绝)的值
promise.any
promise.any接收一个promise可迭代对象,只要其中一个promise成功,就返回那个已经成功的promise,如果可迭代对象中没有一个promise成功(即所有的promise都是失败/拒绝),就返回一个失败的promise和AggrefateError类型的实例(时Error的一个子类),用于把单一的错误集合在一起,本质上,这个方法与promise.all是相反的
参数
一个可迭代对象
返回值
- 如果传入的参数是一个空的可迭代对象,则返回一个已失败状态的promise
- 如果传入的参数不包含任何promise,则返回一个异步完成的promise
- 其他情况下都会返回一个处理中的promise,只要传入的迭代对象中任何一个promise便成功状态,或者其中的所有promise都是失败,那么返回的promise就会异步的(当调用栈为空时)变成成功/失败的状态
注意
- 这个方法用于返回第一个成功的promise,只要一个promise成功此方法就会终止,它不会等待其他的promise全部完成
- 不想promise.all()会返回一组完成值那样,我们只能得到一个成功之(假设至少有一个promise完成),当我们只需要一个promise成功,而不关心是哪一个成功时这个方法很有用
- 和promse.race不一样总是返回第一个结果值,这个方法返回的是第一个成功的值,这个方法会忽略掉所有被拒绝的promise,直到第一个promise成功
应用场景
我们有一个获取图片并返回blob函数,我们可以使用promise.any()来获取一些图片并显示第一张有效的图片(即最先resolved的那个promise)
promise手写
//手写promise.all
//当传入的是空数组是返回一个空数组
function all(arr){
return new Promise((resolve, reject) => {
const result = new Array(arr.length).fill(false);
for(let i=0;i<arr.length;i++){
Promise.resolve(arr[i]).then((data)=>{
result[i]=data;
let isfull=result.every(item=>item);
if(isfull) resolve(result);
}).catch((err)=>{
console.log(err);
})
}
resolve([]);
})
}
//手写promise.race
//当传入的是空的可迭代对象,就一直是pending状态
function race(arr){
return new Promise((resolve,reject)=>{
for(const p of arr){
Promise.resolve(p).then(resolve,reject);
}
})
}
//手写promise.allSettled
//返回传入可迭代对象的所有状态
function allSettled(arr){
let res=new Array(arr.length).fill(false);
return new Promise((resolve,reject)=>{
for(let i=0;i<arr.length;i++){
Promise.resolve(arr[i]).then((data)=>{
res[i]={status:'fulfilled',value:data};
res.every(item=>item)&&resolve(res);
}).catch((err)=>{
res[i]={status:'reject',reason:err};
res.every(item=>item)&&resolve(res);
})
}
})
}
//手写promise.any
function any(arr){
let res=new Array(arr.length).fill(false);
return new Promise((resolve,reject)=>{
for(let i=0;i<arr.length;i++){
Promise.resolve(arr[i]).then((data)=>{
resolve(data);
}).catch((err)=>{
res[i]=err;
res.every(item=>item)&&reject(res);
})
}
arr.length==0&&reject([]);
})
}
//测试样例
let array = [
new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 10)
}),
Promise.resolve(22),
Promise.resolve(23),
Promise.resolve(24),
233,
]