什么是Promise
Promise 是一个构造函数,是用来解决JS异步编程(回调地狱)的一种解决方案,怕有些小伙伴不清楚,所以我在本章最后写了案例o.O,下面我们先来了解 Promise 的一些基础知识。
Promise 特点
-
对象的状态不受外界的影响
Pending (进行中)Fulfilled (已成功)Rejected (已失败)
-
状态的固化(状态一旦发生改变就不会再改变)
Pending -> Fulfilled Pending -> Rejected
Promise 创建
-
构造函数接收一个
executor
的函数作为参数。该函数的两个参数resolve
和reject
,它们都是函数,用来改变 Promise 对象的状态。resolve
是将Promise对象的状态由‘进行中’ 变为 ‘成功’Pending -> Fulfilled
,在异步操作成功时调用,并将成功的结果作为参数传递给对应的回调函数。reject
是将Promise对象状态由‘进行中’ 变为 ‘失败’Pending -> Rejected
,在异步操作失败时调用,并将失败的信息作为参数传递给对应的回调函数。 -
executor
函数什么时候执行呢?let promise = new Promise((resolve, reject) => { console.log(1); }) console.log(2); // 1 2 // 在 new 创建 promise 实例时立即调用。
-
在Promise实例生成后,可以通过调用
then()
方法来绑定异步操作成功/失败的回调函数。then()
方法接收两个回调函数作为参数,第一个参数必选,Promise 对象成功状态的回调函数,第二个参数可选,Promise 对象失败状态的回调函数。let promise = new Promise((resolve, reject) => { setTimeout(() =>{ Math.random() * 100 > 60 ? resolve('及格') : reject('不及格'); }, 300) }) promise.then((result) => { console.log(result); }, (reason) => { console.log(reason); })
-
执行顺序,我们发现输出的顺序是
1 -> 3 -> 2
,Promise 新建后立即执行,所以先输出 1,然后通过resolve
改变Promise对象的状态来调用then()
方法中对应的回调函数是异步操作,所以会等待当前脚本所有的同步任务执行完成后才执行,所以先打印3,最后才是2。let promise = new Promise((resolve,reject) => { console.log(1); resolve(2); }) promise.then((res) => { console.log(res); }) console.log(3); // 1 3 2
与定时器异步的区别
-
首先先简单提一下JS代码的执行过程:同步的进入主线程,异步会的进入Event Table并注册函数。当指定的事情完成时,Event Table会将这个函数移入Event Queue。主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。上述过程会不断重复,也就是常说的Event Loop(事件循环)。
-
JS 异步代码中,分为宏任务与微任务,他们分别有自己的任务队列。微任务:promise、process.nextTick();宏任务:setTimeout、setInterval, Ajax,DOM事件。这里就存在一个优先级的问题,当主线程空闲时间,会先检查微任务队列,然后再走宏任务队列。所以下面的代码执行顺序就是
2 -> 4 -> 3 -> 1
setTimeout(() => { console.log(1); }, 30) let promise = new Promise((resolve, reject) => { console.log(2); resolve(3); }) promise.then((res) => { console.log(res); }) console.log(4);
then方法链式调用
-
then()
方法的作用是为 Promise 实例添加成功和失败状态的回到函数,会返回一个新的 Promise 实例,所以then()
方法后面可以继续跟另一个then()
方法进行链式调用。let promise = new Promise((resolve, reject) => { resolve(1); }) promise.then((result) => { console.log(result); return 2; }, (reason) => { console.log(reason); }) .then((result) => { // 上一次then的返回值作为这次的参数,没有则为 undefined console.log(`then2: ${result}`); })
-
如果前一个
then()
方法中的回调返回的是一个 Promise 实例,这时下一个then()
方法中的回调会根据前一个的 Promise 实例的状态来进行调用。let p = new Promise((resolve, reject) => { resolve('success'); }) p.then((result) => { console.log(result); // -> 'success' return new Promise((resolve, reject) => { reject(`error-.-`); }) }) .then((result) => { console.log(result); // -> 不走这里因为上一次返回的 Promise 状态为 Rejected }, (reason) => { console.log(reason); // -> 'error-.-' })
catch方法
-
用于指定发生错误时的回调函数,就等同于
then()
方法的第二个回调函数。let promise = new Promise((resolve, reject) => { resolve(data); }) // 因为then方法第一个参数是必选项,又用不到所以就填一个null promise.then(null, (reason) => { console.log(reason); }) // === promise.then((res) => { console.log(res); }) .catch((err) => { console.log(err); })
状态固化
-
Promise 对象状态一旦发生改变,就不会再变。
let promise = new Promise((resolve, reject) => { resolve('Fulfilled'); // 将状态改为 Fulfilled console.log(data); // 再抛出错误也不会改变状态 }) promise.then(res => console.log(res)) .catch(err => console.log(err)); // 捕获不到 // -> Fulfilled
状态依赖
-
当前 p2 的状态依赖于 p1 的状态,就会导致自身的状态失效。
let p1 = new Promise((resolve, reject) => { setTimeout(() => { reject('fail') }, 1000) }) let p2 = new Promise((resolve, reject) => { setTimeout(() => { resolve(p1) }, 500) }) p2.then(res => console.log(res)) .catch(err => console.log(err)); // -> fail
all和race
-
都是 Promise 构造器上的方法,
Promise.all()
,可以将多个 Promise 实例包装成一个新的Promise 实例。成功与失败的返回值是不同的,当所有的都成功时返回的结果是一个数组,失败时返回最先触发失败状态的错误信息。 -
注意:
Promise.all()
获取的成功结果的数组里的数据与传入时的顺序是一致的。let promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('peace'); }, 1000) }) let promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('and'); }, 2000)}) let promise3 = new Promise((resolve, reject) => { setTimeout(() => { resolve('love'); }, 300) }) let p = Promise.all([promise1, promise2, promise3]); console.log(p); p.then(res => console.log(res)) // -> ["peace", "and", "love"] .catch(err => console.log(`reject: ${err}`));
-
Promise.race()
,与Promise.all()
的用法相同,但是功能不同,它是获取最快返回结果的那一个,无论结果本身是成功态还是失败状态。let promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('peace'); }, 1000) }) let promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('and'); }, 2000)}) let promise3 = new Promise((resolve, reject) => { setTimeout(() => { resolve('love'); }, 300) }) let p = Promise.race([promise1, promise2, promise3]); console.log(p); p.then(res => console.log(res)) // -> love .catch(err => console.log(`reject: ${err}`));
解决回调地狱问题
// 在无 Promise 之前 node环境读取文件
const fs = require('fs');
// 这种代码非常的不好维护
fs.readFile('./name.txt', 'utf-8', (err, data) => {
if(data){
fs.readFile(data, 'utf-8', (err, data) => {
if(data){
fs.readFile(data, 'utf-8', (err, data) => {
console.log(data);
})
}
})
}
})
// Promise化管理
function readFile (path) {
return new Promise((resolve, reject) => {
fs.readFile(path, 'utf-8', (err, data) => {
if(data){
resolve(data);
}
})
})
}
readFile('./name.txt').then(data => return readFile(data))
.then(data => return readFile(data))
.then(data => console.log(data))
// 将传入的函数Promise化
function promisify (fn) {
return function (...args) {
return new Promise((resolve, reject) => {
fn(...args, (err, data) => {
if(err){
reject(err);
}else{
resolve(data);
}
})
})
}
}
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!