一、Promise是啥?
Promise是异步编程的一种优雅的解决方案。它相比于回调和事件交互,更加合理和强大。它改善了深度回调的问题。 回调里面还有回调,层级较深的,代码看起来特别凌乱。而通过事件交互会多做一些工作,比如发送事件,监听事件,事件回调等操作。而Promise能够获取异步操作的结果,这样的话,方便进一步处理接下来的逻辑。
Promise,简单来说,他就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。ES6将其写进了语言标准,并原生提供了Promise对象。
Promise的特点
- 对象的状态不受外界影响,Promise对象代表一个异步操作,有三种状态:Pending(进行中)、FulFilled(已成功)和Rejected(已失败),任何其他操作都无法改变这个状态。这也就是“Promise”这个名字的由来,它在英文中意思为“承诺”,表示其他手段无法改变。
- 一旦状态改变就不会再变。任何时候都可以得到这个结果。Promise对象的状态改变只有两种可能:从Pending到Fulfilled,或者从Pending到Rejected。只要这两种情况发生,状态就不会再改变。
有了Promise对象,就可以将异步操作以同步操作的流程表达出来。避免了层层嵌套的回调。此外Promise对象还对外提供了统一的接口,使控制异步操作更加容易。
Promise也有一些缺点,它一旦开始他就会立即执行,并且无法取消。这个很Promise!
其次,如果不设置回调函数,Promise内部的异常不会反应到外部,也就是说内部出错了也不知道。再者,当处于Pending状态时,无法得知目前进展到哪一步,是刚刚开始,还是即将完成
二、怎么使用Promise?
ES6规定,Promise对象是一个构造函数,用来生成Promise对象。 下面的代码反映了Promise的基本用法。
代码语言:javascript复制var promise = new Promise(function(resolve,reject){
//some code
if(操作成功){
resolve(value);
}else{
reject(error);
}
})
Promise的构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject,他们是两个函数,是由JavaScript引擎提供,不用开发者自己部署。
resolve的作用是,将Promise从未完成(Pending)状态变成已成功(Fulfilled)状态,在异步操作成功时调用,并把异步操作的结果作为参数传递出去。 reject的作用是将Promise从未完成(Pending)状态变成已失败(Rejected)状态,在异步操作失败时调用,并把异步操作的错误作为参数传递出去。
Promise.prototype.then
Promise实例具有then方法,then方法是定义在Promise.prototype上的,它的作用是为Promise实例添加状态回调改变时的回调函数。then的第一个参数是Resolved状态的回调函数,第二个参数(可选)是Rejected状态下的回调函数。then方法返回的是一个新的Promise对象。注意,不是原来的那个Promise对象,因此可以采用链式写法,即then方法后面还可以再调用then方法。
举个栗子吧
代码语言:javascript复制let promise = new Promise((resolve, reject) => {
console.log("Promise!");
resolve();
console.log("Promise Over");
})
setTimeout(() => {
console.log("Hello World!");
}, 0)
console.log("Hi!");
promise.then(() => {
console.log("Resolved!");
})
运行截图如下:
我们来分析下运行结果: promise一旦被创建,就会立即执行,那么代码同步执行,首先就会输出Promise,接下来就会输出Promise Over;因为Promise一系列的操作(then、catch)优先级比setTimeout要高,然后在执行Promise.then,所以接下来是输出Resolved!,最后执行setTimeout,输出Hello World。
Promise.prototype.catch
Promise.prototype.catch方法是.then(null,reject)的别名,用于指定发生错误的回调。catch可以捕捉到在它之前所有的promise对象内部抛出的异常。
举个栗子:
代码语言:javascript复制var doSomething = () => {
return new Promise((resolve, reject) => {
console.log("doSomething");
resolve(1 x);
console.log("doSomething over");
})
}
doSomething().then((value) => {
console.log(value)
}).catch((err) => {
console.log("hhhhhh");
console.log(err);
})
运行截图如下:
Promise.all
Promise.all方法是将多个Promise实例包装成一个新的Promise实例。
代码语言:javascript复制var p = Promise.all([p1,p2,p3])
上面代码中,Promise.all方法接受一个数组作为参数,p1、p2、p3都是Promise对象的实例,如果不是,就会先调用下面讲到的Promise.resolve方法, 将参数转为Promise实例,再进一步处理。(Promise.all方法的参数可以不是数组,但必须具有Iterator接口,且返回的每个成员都是Promise实例。)
p的状态由p1、 p2、 p3决定, 分成两种情况。 (1)只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled,此时p1、 p2、 p3的返回值组成一个数组,传递给p的回调函数。 (2)只要p1、p2、p3之中有一个被rejected,p的状态就变成rejected,此时第一个被reject的实例的返回值, 会传递给p的回调函数
举个栗子:
代码语言:javascript复制let promise1 = new Promise(resolve => {
console.log("promise1");
resolve(1);
})
let promise2 = new Promise(resolve => {
console.log("promise2");
resolve(2);
})
let promise3 = new Promise(resolve => {
console.log("promise3");
resolve(3);
})
let promises = [promise1, promise2, promise3];
Promise.all(promises).then(value => {
console.log(value);
}).catch(err => {
console.log(err);
})
运行截图:
再看一个栗子:
代码语言:javascript复制let promise1 = new Promise(resolve => {
console.log("promise1");
resolve(1);
})
let promise2 = new Promise(resolve => {
console.log("promise2");
resolve(2);
})
let promise3 = new Promise(resolve => {
console.log("promise3");
resolve(x 3);
}).then((value) => {
console.log(value);
})
let promises = [promise1, promise2, promise3];
Promise.all(promises).then(value => {
console.log(value);
}).catch(err => {
console.log("promise all err:", err);
})
运行截图:
分析: 在上面的代码中,promise1、promise2都正常变为resolved状态,promise3中会发生错误,状态变为Rejected。导致Promise.all这个Promise也会变为Rejected状态。所以会执行Promise.all后面的catch方法,所以在打印promise1,promise2,promise3之后,还会打印promise all err。
再再看一个栗子:
代码语言:javascript复制let promise1 = new Promise(resolve => {
console.log("promise1");
resolve(1);
})
let promise2 = new Promise(resolve => {
console.log("promise2");
resolve(2);
})
let promise3 = new Promise(resolve => {
console.log("promise3");
resolve(x 3);
}).then((value) => {
console.log(value);
}).catch((err) => {
console.log("promise3 err:", err);
})
let promises = [promise1, promise2, promise3];
Promise.all(promises).then(value => {
console.log(value);
}).catch(err => {
console.log("promise all err:", err);
})
运行截图:
分析:promise1,promise2都会进入resolved状态,到了promise3,promise3中有错误,那么会执行promise3后面的catch方法,而catch方法会返回一个新的Promise实例,promise3指向了这个新的promise实例。这个实例在执行完catch之后,也会变成resolved的状态。所以promise1、promise2、promise3都进入了resolved状态,那么Promise.all会执行后面的then方法,但是promise1,promise都有返回值,promise3没有返回值,所以打印出来是[1,2,undefined]。
Promise.race
Promise.race方法也是将多个Promise实例包装成一个新的Promise实例。
代码语言:javascript复制var p = Promise.race([p1,p2,p3])
上面代码中, 只要p1、 p2、 p3之中有一个实例率先改变状态, p的状态就跟着改变。 那个率先改变的Promise实例的返回值, 就传递给p的回调函数。 Promise.race方法的参数与Promise.all方法一样, 如果不是Promise实例, 就会先调用下面讲到的Promise.resolve方法, 将参数转为Promise实例, 再进一步处理。
举个栗子:
代码语言:javascript复制let promise1 = new Promise(resolve => {
console.log("promise1");
resolve(1);
})
let promise2 = new Promise(resolve => {
console.log("promise2");
resolve(2);
})
let promise3 = new Promise(resolve => {
console.log("promise3");
resolve(3);
})
let promises = [promise1, promise2, promise3];
Promise.race(promises).then(value => {
console.log(value);
}).catch(err => {
console.log(err);
})
运行截图:
Promise.resolve
Promise.resolve的作用就是将一个对象转换成Promise对象。
Promise.resolve方法的参数分成为以下4种情况。
- 参数是一个Promise实例 如果参数是Promise实例,那么Promse.resolve将不做任何修改,原封不动的返回这个实例。
- 参数是一个thenable对象 thenable对象指的是具有then方法的对象。比如下面这个对象let thenable = { then:function(resolve,reject){ resolve(12); } } let p = Promise.resolve(thenable); p.then((value)=>{ console.log(value); }) Promise.resolve方法会将这个对象转换成Promise对象,然后立即执行thenable对象的then方法。 所有上面的代码,结果会输出12。
- 参数不是具有then方法的对象或者根本不是对象 如果参数是一个原始值,或者是一个不具有then方法的对象,那么Promise.resolve会返回一个新的Promise对象,状态为resolvedvar p = Promise.resolve("Hello"); p.then((s)=>{ console.log(s) }) 上述代码会输出Hello。
- 不带有任何参数 Promise.resolve允许在调用时,不带任何参数。而直接返回一个Resolved状态的Promise对象。 需要注意,立即resolve的Promise对象是在本轮事件循环结束时么不也是下一轮事件循环开始时。 举个栗子:setTimeout(() => { console.log("xxxx"); }, 0); Promise.resolve().then(() => { console.log("yyyyy"); }) console.log("zzzz"); 运行截图:
Promise.reject
Promise.reject(reason)方法也会返回一个新的Promise实例,状态为Rejected。
Promise.finally
finally方法用于指定不管Promise对象最后状态如何都会执行的操作。
举个栗子:
代码语言:javascript复制let p2 = new Promise((resolve, reject) => {
resolve(1);
})
p2.then((value) => {
console.log(value);
}).catch((err) => {
console.log("error:", err);
}).finally(() => {
console.log("finally");
})
输出: 1 finally
那么,Promise,你熟悉它了吗?后面还会有关于Promise的故事,敬请期待~
如有错漏,欢饮大佬们拍砖~