让我们通过下面的例子来理解 Promise 是什么。我明天预约了一个位客户来公司洽谈业务,客户承诺明天会来我们公司。但是实际明天回有两个结果,1 是客户信守诺言来到我们公司,2 是客户因为其他事情没有兑现承诺来拜访我们公司。这个例子很好的表达了Promise函数的两种结果,遵守承诺的结果(this在Promise中resolved)和不遵守承诺的结果(this在Promise中rejected)。Promise函数最基础的规则就是在遵守承诺或者不遵守承诺的结果中一定会返回一种结果,可以总结为 “一个Promise会有两个结果并返回其中一个结果”。
“一个Promise会有两个结果并返回其中一个结果”这句话是什么意思呢?现在我们来使用Promise的代码来解释它。首先使用 new 运算符实例化 Promise 对象并将其分配给变量 zhtuser。
let zhtuser = new Promise()
一个标准的Promise 的函数中包含两个回调函数 resolve 和 reject。
let zhtuser = new Promise(function(resolve,reject){//业务处理内容
})
在定义resolve 和 reject两个回调函数的业务代码,如果遵守承诺执行 resolve 函数中的逻辑,如果不遵守则将值执行 reject 中的业务逻辑。
const is_promise = true
const zhtuser = new Promise(function(resolve,reject){if (is_promise){resolve('客户来了')} else {reject('客户没有来')}
})
这就是编写一个 Promises 函数的主要内容。Promises 函数根据 is_promise的值来决定返回 resolve 或 reject 的值。我们还可以使用函数编写的方式来写自定义的Promise函数调用 resolve 和 reject 。
const is_promise = true
const zhtuser = function (){return new Promise(function(resolve,reject){if (is_promise){resolve('客户来了')} else {reject('客户没有来')} })
}
========== javasrcipt函数 ============
function zhtuser() {return new Promise(function(resolve,reject){if (is_promise){resolve('客户来了')} else {reject('客户没有来')} })
}
现在我们知道了如何创建一个Promise 承诺函数,那么我们如何来操作Promise函数?这时需要使用到 then方法,来帮助我们在zhtuser对象中获得Promise resolve 的结果。
Then方法中包含了一个函数,这个函数的参数就是 resolve 的结果。
const is_promise = true
const zhtuser = new Promise(function(resolve,reject){if (is_promise){resolve('客户来了')} else {reject('客户没有来')}
})
//执行获得resolve函数结果
zhtuser.then(function(comment){alert(comment)
})
回调resolve
函数中的参数现在是字符串,它也可以是对象,数组,或者是所有javascript对象类型。现在让我们看看将一个数组放入 resolve 会发生什么。
const is_promise = true
const zhtuser = new Promise(function(resolve,reject){if (is_promise){resolve(['a','b','c',1,2,3])} else {reject('客户没有来')}
})
zhtuser.then(function(comment){alert(comment)
})
我们使用then方法同样可以获得到数组内容。
[ 'a', 'b', 'c',1,2,3]
如果未遵守承诺(is_promise= false),我们将如何获取 reject 中的值。
**如果is_promise= false,使用 catch 而不是 then 来获取 reject 的值。**这样可以根据结果进行不同的业务处理,如果遵守诺言则在 then 中执行业务代码,如果不遵守诺言则在 catch 中执行业务代码。
const is_promise = false
const zhtuser = new Promise(function(resolve,reject){if (is_promise){resolve(['a','b','c',1,2,3])} else {reject('客户没有来')}
})
//业务执行
zhtuser.then(function(comment){alert(comment)//如果没有遵守承诺获得 reject 中的值
}).catch(function(comment){alert(comment)
})
我开发的时候通常会直接使用catch方法,但是你也可以在then中放入两个函数,不需要使用catch方法也可以得到reject值。
const is_promise = false
const zhtuser = new Promise(function(resolve,reject){if (is_promise){resolve(['a','b','c',1,2,3])} else {reject('客户没有来')}
})
========== 第二个函数是reject ============
zhtuser.then(
function(comment){alert(comment)
},function(comment){alert(comment)
})
Promises 函数最常见的应用是通过axios获得外部资源的数据。我们在开发中常常会看到axios操作中会使用到then与catch方法,这就最典型的Promises 函数操作。
axios.get('/api').then(function(response){//访问成功后进入
}).catch(function(error){//访问失败后进入
});
通过上面的学习,我们能够理解了Promises 功能中这些 resolve、reject、then、catch 方法。
Promises中有三种状态它们分别是pending(待定), fulfilled(完成), rejected(拒绝)。使用 Chrome 的开发者工具可以直观地看到Promises中的所属状态。
const is_promise = false
const zhtuser = new Promise(function(resolve,reject){if(is_promise){resolve(['a','b','c',1,2,3])} else {reject('客户没有来')}
})
console.log(zhtuser);
1 拒绝状态
从目前提到的resolve和reject来看,fulfill状态是指遵守promise时的状态,返回reslove的值,rejected状态是指不遵守promise时的状态,返回reject的值。去做。
Promise[[Prototype]]:
Promise[[PromiseState]]:"rejected"
[[PromiseResult]]: "客户没有来"
2 完成状态
将is_promise值设置成true ,在开发者工具中可以看到完成状态。
const is_promise = true
const zhtuser = new Promise(function(resolve,reject){if(is_promise){resolve(['a','b','c',1,2,3])} else {reject('客户没有来')}
})
console.log(zhtuser);
================= 后台打印 =================
Promise {: Array(6)}
[[Prototype]]:
Promise[[PromiseState]]: "fulfilled"
[[PromiseResult]]: Array(6)
3 待定状态
让我们来看一下 pending 等待状态是什么意思,它标识在promise代码中还没执行完成,程序还无法判断promise返回resolve和reject时候的状态。就是程序还没有决定返回resolve或者reject时候的状态。让我们使用setTimeout函数制作出一个pendig状态,并在5秒后返回一个resolve或者reject的结果。
const is_promise = true
const zhtuser = new Promise(function(resolve,reject){setTimeout(function(){if (is_promise){resolve('返回成功resolve')} else {reject('返回拒接reject')}},1000*5)})
console.log(zhtuser);
查看开发者工具,在 5 秒等待时间中状态会是 pending。 5 秒过后开发者工具中将显示状态resolve 或 reject。
Promise {}
[[Prototype]]:
Promise[[PromiseState]]: "pending"
[[PromiseResult]]:
现在大家应该能够理解 promise中的 resolve、reject、then、catch、fulfilled、rejected、pending 这些关键字的含义了。那么Promise函数一般会在什么情况下来使用?
创建一个从上到下依次进行的过程,console中的内容的也会按顺序打印在控制台,这称为同步处理。
console.log('流程1')console.log('流程2')console.log('流程3')console.log('流程4')
我们将其中的一些console打印时间停顿二秒钟在打印出来。使用 setTimeout 函数停顿2秒后打印在控制台,这称为异步处理。
console.log('流程1')
setTimeout(() => {console.log('流程2')
},2000)
setTimeout(() => {onsole.log('流程3')
},2000)
console.log('流程4')
由于这里指定了setTimeout函数设置了停顿的时间,但是在很多场景中我们是不知道停顿时间的,在不知道停顿时间情况下就不能使用此方法。这个时候就可以使用Promise来处理这种情况,then 方法会在 resolve 执行后运行,我们会使用到这个特性。
console.log('流程1')
new Promise((resolve) => {setTimeout(() => {console.log('流程3')resolve()},2000)
}).then(() => {console.log('流程2')
})console.log('流程4')后台打印结果
流程1
流程4
流程3
流程2
在 Promise 内部处理 setTimeout 时候 Promise 状态为 Pending。当 Promise 进入(fulfilled)状态时,then方法会被resolve执行,执行顺序是流程3在流程2。这样异步处理过程也可以像同步一样来完成了。
如果执行完流程3出现问题,流程终止不在执行流程2。这个功能可以使用 reject 和 catch来完成。
console.log('流程1')
new Promise((resolve,reject) => {setTimeout(() => {console.log('流程3')reject('流程结束')},2000)
}).then(() => {console.log('流程2')
}).catch((error) => {console.log(error)
})
console.log('流程4')
后台打印结果
流程1
流程4
流程3
流程结束
很多开发者在使用 fetch 函数和 axios 库或者其他异步处理的函数时,都会遇到“返回Promise函数”这提示词。因为这些异步函数中很多都使用了Promise 作为它们的返回值类型。
我们来写一段fetch函数访问URL的代码,在浏览器的控制台中会如何执行的。
fetch('https://jsonplaceholder.typicode.com/todos/1').then(response => {console.log(response)
})
控制台在等待一段时间后执行了 console.log(response)。由于 fetch 函数是通过网络从 JSONPlaceHolder 中获取数据,因此无法立即获取到数据。在控制台中可以看到响应值是一个 Promise。因为fetch 函数帮我们处理了 resolve 和 reject封装过程,我们就不需要在编写 resolve 和 reject 的相关逻辑代码了。
Response {type: 'cors', url: 'https://jsonplaceholder.typicode.com/todos/1', redirected: false, status: 200, ok: true, …}
"https://jsonplaceholder.typicode.com/todos/1"
[[Prototype]]
Response
我们在使用有“返回Promise”的函数或者方法的时候,只需要使用then 和 catch 来做进一步的逻辑处理就可以了。不在需要关心它们内部的resolve 和 reject 代码如何编写的,直接拿来使用就可以了。
Promise 可以可以相互链接在一起进行使用。我们可以将它们级联在一起,在执行一个Promise 过程之后,可以将该过程的结果传递给下一个Promise 继续执行。通过下面的例子大家能更好的体会Promise 级联执行的过程。
const is_flag1 = true
const is_flag2 = true
const z1 = new Promise(function(resolve,reject){if (is_flag1){resolve('流程执行')} else {reject('流程结束')}
})
const z2 = function(comment){return new Promise(function(resolve,reject){if (is_flag2){resolve(comment + ' 流程1')} else {reject(comment + ' 流程2')}})
}
z1.then(z2).then(function(z2){console.log(z2)
})
.catch(function(z2){console.log(z2)
})
后台打印结果
流程执行 流程1
让我们根据is_flag1和is_flag2的状态值来控制Promise 流程走向。
const is_flag1 = true
const is_flag2 = true
流程执行 流程1
==========================
const is_flag1 = true
const is_flag2 = false
流程执行 流程2
==========================
const is_flag1 = false
const is_flag2 = true
流程结束
==========================
const is_flag1 = false
const is_flag2 = false
流程结束
2 Promise多个then使用
我们可以在 Promise 函数中连接多次使用它的then函数。下面的代码中我连接了三个then方法, 3 秒后将显示6这个数字。从下面的代码中可以看出的前面的then方法结果会传递给了后面的then。
const addNumber = function(number) {return new Promise(function(resolve){setTimeout(() => {resolve(number + 1);}, 1000);});
};
addNumber(3).then(addNumber).then(addNumber).then(function(number){console.log(number)
})
后台打印结果
6
当 Promise 被级联时候,Promise 的引用可以被当成参数传递到一下个 then方法中,then方法中的返回值就是下一个then的参数。
在下面的示例中,addNumber(1) 被执行并且 resolve 返回 2。将 2 传递给下一个 then,下一个 then 返回 4。返回值传递给下一个then,执行4*3。在将值传递给一下个then,执行12 乘4。
const addNumber = function(number) {return new Promise(function(resolve){setTimeout(() => {//number 2resolve(number + 1);}, 1000);});
};
addNumber(1).then(function(number){//number=2 2*2=4return number*2
}).then(function(number){//number=4 4*3=12return number*3
}).then(function(number){//number=12 4*12=48return number*4
}).then(function(number){console.log(number)
})
后台打印结果
48
大家需要明白的是我们不仅使用Promise的resolve来传值给then,还还可以通过return把值传给下一个then。
Promise.all函数
使用Promise.all函数可以一次接收处理多个 Promise 的结果。
const addNumber = function(number) {return new Promise(function(resolve){setTimeout(() => {resolve(number + 1);}, 1000);});
};
Promise.all([addNumber(1),addNumber(2),addNumber(3)]).then(function(result){console.log(result)
})
下一篇:十七、队列