하나의 기사로 약속/비동기 대기를 이해하고 70% 이상의 프런트 엔드 인력을 따라잡으세요.
오늘은 Promise를 공유하겠습니다. 저자는 초기 비동기 코드의 딜레마, Promise의 출현으로 어떤 문제가 해결되었는지, 비동기 콜백 지옥에 대한 궁극적인 해결책, 실제로 Async Wait의 핵심 구문을 구현해 보겠습니다. , async/await는 Generator+promise의 변형일 뿐입니다.
1. 초기 비동기 코드의 딜레마
- 우리 모두 알고 있듯이 js는 단일 스레드이며 시간이 많이 걸리는 작업은 시간이 지나면 브라우저에서 처리됩니다. 실행을 위한 큐와 이벤트 루프의 개념도 작성자가 공유했습니다. 아래에서 읽어보시면
promise
를 더 잘 이해할 수 있습니다.promise
。 - 我以一个需求为切入点,我模拟网络请求(异步操作)
- 如果网络请求成功了,你告知我成功了
- 如果网络请求失败了,你告知我失败了
1.1 大聪明做法
function requestData(url) { setTimeout(() => { if (url === 'iceweb.io') { return '请求成功' } return '请求失败' }, 3000) } const result = requestData('iceweb.io') console.log(result) //undefined
- 首先你要理解
js
代码的执行顺序,而不是是想当然的,代码其实并不是按照你书写的顺序执行的。 - 那么为什么是
undefined呢
?- 首先当我执行
requestData
函数,开始执行函数。遇到了异步操作不会阻塞后面代码执行的,因为js是单线程的,所以你写的return
成功或者失败并没有返回,那我这个函数中,抛开异步操作,里面并没有返回值,所以值为undefined
。
- 首先当我执行
2.2 早期正确做法
function requestData(url, successCB, failureCB) { setTimeout(() => { if (url === 'iceweb.io') { successCB('我成功了,把获取到的数据传出去', [{name:'ice', age:22}]) } else { failureCB('url错误,请求失败') } }, 3000) } //3s后 回调successCB //我成功了,把获取到的数据传出去 [ { name: 'ice', age: 22 } ] requestData('iceweb.io', (res, data) => console.log(res, data), rej => console.log(rej)) //3s后回调failureCB //url错误,请求失败 requestData('icexxx.io', res => console.log(res) ,rej => console.log(rej))
- 早期解决方案都是传入两个回调,一个失败的,一个成功的。那很多开发者会问这不是挺好的吗?挺简单的,js中函数是一等公民,可以传来传去,但是这样太灵活了,没有规范。
- 如果使用的是框架,还要阅读一下框架源码,正确失败的传实参的顺序,如果传参顺序错误这样是非常危险的。
2. Promise
-
Promise
(承诺),给予调用者一个承诺,过一会返回数据给你,就可以创建一个promise对象 - 当我们
new
一个promise
,此时我们需要传递一个回调函数,这个函数为立即执行的,称之为(executor) - 这个回调函数,我们需要传入两个参数回调函数,
reslove
,reject
(函数可以进行传参)- 当执行了
reslove
函数,会回调promise对象的.then函数 - 当执行了
reject
函数,会回调promise对象的.catche函数
- 当执行了
2.1 Executor立即执行
new Promise((resolve, reject) => { console.log(`executor 立即执行`) })
- 传入的
executor
是立即执行的
2.2 requestData 重构
function requestData(url) { return new Promise((resolve, reject) => { setTimeout(() => { if (url === 'iceweb.io') { //只能传递一个参数 resolve('我成功了,把获取到的数据传出去') } else { reject('url错误,请求失败') } }, 3000) }) } //1. 请求成功 requestData('iceweb.io').then(res => { //我成功了,把获取到的数据传出去 console.log(res) }) //2. 请求失败 //2.2 第一种写法 //url错误,请求失败 requestData('iceweb.org').then(res => {},rej => console.log(rej)) //2.2 第二种写法 //url错误,请求失败 requestData('iceweb.org').catch(e => console.log(e))
- 在函数中,new这个类的时候,传入的回调函数称之为
executor
(会被Promise类中自动执行) - 在正确的时候调用
resolve
函数,失败的时候调用reject
函数,把需要的参数传递出去。 - 异常处理
- 其中在
.then
方法中可以传入两个回调,您也可以查看Promise/A+规范- 第一个则是
fulfilled
的回调 - 第二个则是
rejected
的回调
- 第一个则是
- 其中在
- 那这样有什么好处呢? 看起来比早期处理的方案还要繁琐呢?
统一规范,可以增强阅读性和扩展性
小幅度减少回调地狱
2.3 promise的状态
- 首先先给大家举个栗子,把代码抽象为现实的栗子
- 你答应你女朋友,下周末带她去吃好吃的 (还未到下周末,此时状态为待定状态)
- 时间飞快,今天就是周末了,你和你女友一起吃了烤肉、甜点、奶茶...(已兑现状态)
- 时间飞快,今天就是周末了,正打算出门。不巧产品经理,因为线上出现的紧急问题,需要回公司解决一下,你(为了生活)只能委婉的拒绝一下女友,并且说明一下缘由(已拒绝状态)
- 使用
promise
的时候,给它一个承诺,我们可以将他划分为三个阶段- pending(待定),执行了executor,状态还在等待中,没有被兑现,也没有被拒绝
- fulfilled(已兑现),执行了
resolve
函数则代表了已兑现状态 - rejected(已拒绝),执行了
reject
요구사항을 시작점으로 사용하여 네트워크 요청(비동기 작업)을 시뮬레이션합니다.
네트워크 요청이 성공하면 성공했다고 알려줍니다. - 네트워크 요청이 실패하면 실패했다고 알려줍니다
🎜1.1 현명한 접근🎜
const promise = new Promise((resolve, reject) => { setTimeout(() => { reject('失败') resolve('成功') }, 3000); }) promise.then(res => console.log(res)).catch(err => console.log(err)) //失败
js
코드의 실행 순서를 이해해야 합니다. 코드는 실제로 작성한 순서를 따르지 않습니다. 🎜🎜그럼 왜 정의되지 않음
인가요? 🎜🎜먼저 requestData
함수를 실행하면 함수 실행이 시작됩니다. 비동기 작업이 발생하면 js가 단일 스레드이기 때문에 다음 코드의 실행을 차단하지 않으므로 작성한 return
은 성공하거나 실패하더라도 반환되지 않습니다. 비동기 작업은 제쳐두고, 내부에는 반환 값이 없으므로 값이 정의되지 않음
입니다. 🎜🎜🎜🎜🎜2.2 초기 올바른 접근 방식🎜
const promise = new Promise((resolve, reject) => { resolve({name: 'ice', age: 22}) }) promise.then(res => console.log(res)) // {name: 'ice', age: 22}
🎜2. Promise🎜🎜🎜🎜Promise
(약속), 호출자에게 약속을 하고 잠시 후 데이터를 반환합니다. Promise 개체🎜🎜promise
를 새
할 때 콜백 함수를 전달해야 합니다. 이 함수는 즉시 실행되고 (executor)🎜🎜 호출됩니다. , 콜백 함수에 reslove
, reject
라는 두 개의 매개변수를 전달해야 합니다(함수는 매개변수를 전달할 수 있음)🎜🎜reslove
가 실행될 때 > 함수는 Promise 개체의 .then 함수를 호출합니다🎜🎜reject
함수가 실행되면 Promise 개체의 .catche 함수가 다시 호출됩니다🎜🎜🎜🎜 🎜2.1 Executor가 즉시 실행됩니다🎜
const promise = new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ice')
}, 3000);
}))
})
promise.then(res => console.log(res))
//3s后 ice
로그인 후 복사로그인 후 복사🎜🎜들어오는 executor
가 즉시 실행됩니다🎜🎜🎜2.2 requestData 재구성🎜 h3>const promise = new Promise((resolve, reject) => {
resolve({
then(res, rej) {
res('hi ice')
}
})
})
promise.then(res => console.log(res))
// hi ice
로그인 후 복사로그인 후 복사🎜🎜함수에서 이 클래스가 새로 생성되면 전달된 콜백 함수를 executor
라고 합니다(Promise 클래스에 의해 자동으로 실행됩니다)🎜🎜 적시에 해결
함수는 실패하고 필수 매개변수를 전달하는 경우 reject
함수를 호출합니다. 🎜🎜예외 처리🎜🎜두 개의 콜백이 .then
메서드에 전달될 수 있으며 Promise/A+ 사양🎜🎜첫 번째는 fulfilled
의 콜백🎜🎜두 번째는 rejected
의 콜백🎜 🎜🎜🎜🎜 🎜그렇다면 이것의 장점은 무엇인가요? 초기 솔루션보다 더 번거로워 보이죠?🎜🎜통합 사양으로 가독성과 확장성을 높일 수 있습니다🎜🎜🎜🎜콜백 지옥을 조금 줄입니다🎜🎜 🎜🎜🎜🎜2.3 약속 상태🎜
🎜🎜먼저 예를 들어 코드를 현실적인 예로 추상화하겠습니다🎜🎜여자친구에게 약속합니다. 맛있는 음식을 먹으러 가세요 다음 주말 음식 (아직 다음 주말이 아니고 상태는 🎜대기 상태🎜)🎜🎜시간이 빨리 지나서 오늘이 주말이고 여자친구와 바비큐, 디저트, 밀크티를 먹었어요... (🎜현금상태🎜)🎜🎜 시간이 빨리 가네요. 오늘이 주말인데 외출을 하려고 합니다. 아쉽게도 온라인에서 발생한 긴급한 문제를 해결하기 위해 제품 관리자가 회사에 다시 방문해야 합니다. (생활을 위해) 여자 친구를 정중하게 거절하고 이유를 설명할 수 있습니다(🎜거부 상태🎜)🎜🎜🎜🎜이용하세요. promise
, 약속을 하세요. 세 단계로 나눌 수 있습니다🎜🎜pending(보류 중), 실행자가 실행되고, 상태가 여전히 대기 중이고, 이행되지 않았으며, 거부되지 않았습니다🎜 🎜 이행(fulfilled), resolve
함수 실행은 이행 상태를 나타냅니다. 🎜🎜rejected(거부), reject
함수 실행은 거부됨 상태를 나타냅니다 🎜🎜 🎜🎜우선 , 상태가 보류 상태에서 다른 상태로 변경되는 한 상태는 더 이상 변경할 수 없습니다🎜🎜🎜다음 코드를 생각해 보세요.🎜
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject('失败')
resolve('成功')
}, 3000);
})
promise.then(res => console.log(res)).catch(err => console.log(err))
//失败
로그인 후 복사로그인 후 복사
- 当我调用
reject
之后,在调用resolve
是无效的,因为状态已经发生改变,并且是不可逆的。
2.4 resolve不同值的区别
- 如果
resolve
传入一个普通的值或者对象,只能传递接受一个参数,那么这个值会作为then
回调的参数
const promise = new Promise((resolve, reject) => {
resolve({name: 'ice', age: 22})
})
promise.then(res => console.log(res))
// {name: 'ice', age: 22}
로그인 후 복사로그인 후 복사
- 如果
resolve
中传入的是另外一个Promise
,那么这个新Promise
会决定原Promise
的状态
const promise = new Promise((resolve, reject) => {
resolve(new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ice')
}, 3000);
}))
})
promise.then(res => console.log(res))
//3s后 ice
로그인 후 복사로그인 후 복사
- 如果
resolve
中传入的是一个对象,并且这个对象有实现then
方法,那么会执行该then
方法,then
方法会传入resolve
,reject
函数。此时的promise
状态取决于你调用了resolve
,还是reject
函数。这种模式也称之为: thenable
const promise = new Promise((resolve, reject) => {
resolve({
then(res, rej) {
res('hi ice')
}
})
})
promise.then(res => console.log(res))
// hi ice
로그인 후 복사로그인 후 복사
2.5 Promise的实例方法
- 实例方法,存放在
Promise.prototype
上的方法,也就是Promise的显示原型上,当我new Promise的时候,会把返回的改对象的 promise[[prototype]](隐式原型) === Promise.prototype (显示原型)
- 即new返回的对象的隐式原型指向了Promise的显示原型
2.5.1 then方法
2.5.1.1 then的参数
-
then
方法可以接受参数,一个参数为成功的回调,另一个参数为失败的回调,前面重构requestData
中有演练过。
const promise = new Promise((resolve, reject) => {
resolve('request success')
// reject('request error')
})
promise.then(res => console.log(res), rej => console.log(rej))
//request success
로그인 후 복사
- 如果只捕获错误,还可以这样写
- 因为第二个参数是捕获异常的,第一个可以写个
null
或""
占位
const promise = new Promise((resolve, reject) => {
// resolve('request success')
reject('request error')
})
promise.then(null, rej => console.log(rej))
//request error
로그인 후 복사
2.5.1.2 then的多次调用
const promise = new Promise((resolve, reject) => {
resolve('hi ice')
})
promise.then(res => ({name:'ice', age:22}))
.then(res => console.log(res))
//{name:'ice', age:22}
로그인 후 복사로그인 후 복사
- 调用多次则会执行多次
2.5.1.3 then的返回值
-
then
方法是有返回值的,它的返回值是promise
,但是是promise
那它的状态如何决定呢?接下来让我们一探究竟。
2.5.1.3.1 返回一个普通值 状态:fulfilled
const promise = new Promise((resolve, reject) => {
resolve('hi ice')
})
promise.then(res => ({name:'ice', age:22}))
.then(res => console.log(res))
//{name:'ice', age:22}
로그인 후 복사로그인 후 복사
- 返回一个普通值,则相当于主动调用
Promise.resolve
,并且把返回值作为实参传递到then
方法中。
- 如果没有返回值,则相当于返回
undefined
2.5.1.3.2 明确返回一个promise 状态:fulfilled
const promise = new Promise((resolve, reject) => {
resolve('hi ice')
})
promise.then(res => {
return new Promise((resolve, reject) => {
resolve('then 的返回值')
})
}).then(res => console.log(res))
//then 的返回值
로그인 후 복사
- 主动返回一个
promise
对象,状态和你调用resolve
,还是reject
有关
2.5.1.3.3 返回一个thenable对象 状态:fulfilled
const promise = new Promise((resolve, reject) => {
resolve('hi ice')
})
promise.then(res => {
return {
then(resolve, reject) {
resolve('hi webice')
}
}
}).then(res => console.log(res))
//hi webice
로그인 후 복사
- 返回了一个thenable对象,其状态取决于你是调用了
resolve
,还是reject
2.5.2 catch方法
2.5.2.1 catch的多次调用
const promise = new Promise((resolve, reject) => {
reject('ice error')
})
promise.catch(err => console.log(err))
promise.catch(err => console.log(err))
promise.catch(err => console.log(err))
//ice error
//ice error
//ice error
로그인 후 복사
2.5.2.2 catch的返回值
- catch方法是有返回值的,它的返回值是promise,但是是promise那它的状态如何决定呢?接下来让我们一探究竟。
- 如果返回值明确一个promise或者thenble对象,取决于你调用了
resolve
还是reject
2.5.2.2.1 返回一个普通对象
const promise = new Promise((resolve, reject) => {
reject('ice error')
})
promise.catch(err => ({name:'ice', age: 22})).then(res => console.log(res))
//{name:'ice', age: 22}
로그인 후 복사
2.5.2.2.2 明确返回一个promise
const promise = new Promise((resolve, reject) => {
reject('ice error')
})
promise.catch(err => {
return new Promise((resolve, reject) => {
reject('ice error promise')
})
}).catch(res => console.log(res))
//ice error promise
로그인 후 복사
- 此时
new Promise()
调用了reject
函数,则会被catch
捕获到
2.5.2.2.3 返回thenble对象
const promise = new Promise((resolve, reject) => {
reject('ice error')
})
promise.catch(err => {
return {
then(resolve, reject) {
reject('ice error then')
}
}
}).catch(res => console.log(res))
//ice error then
로그인 후 복사
2.5.3 finally方法
- ES9(2018)新实例方法
- finally(最后),无论promise状态是fulfilled还是rejected都会执行一次
finally
方法
const promise = new Promise((resolve, reject) => {
resolve('hi ice')
})
promise.then(res => console.log(res)).finally(() => console.log('finally execute'))
//finally execute
로그인 후 복사
2.6 Promise中的类方法/静态方法
2.6.1 Promise.reslove
Promise.resolve('ice')
//等价于
new Promise((resolve, reject) => resolve('ice'))
로그인 후 복사
- 有的时候,你已经预知了状态的结果为fulfilled,则可以用这种简写方式
2.6.2 Promise.reject
Promise.reject('ice error')
//等价于
new Promise((resolve, reject) => reject('ice error'))
로그인 후 복사
- 有的时候,你已经预知了状态的结果为rejected,则可以用这种简写方式
2.6.3 Promise.all
const promise = new Promise((resolve, reject) => { resolve(new Promise((resolve, reject) => { setTimeout(() => { resolve('ice') }, 3000); })) }) promise.then(res => console.log(res)) //3s后 ice
const promise = new Promise((resolve, reject) => { resolve({ then(res, rej) { res('hi ice') } }) }) promise.then(res => console.log(res)) // hi ice
executor
라고 합니다(Promise 클래스에 의해 자동으로 실행됩니다)🎜🎜 적시에 해결
함수는 실패하고 필수 매개변수를 전달하는 경우 reject
함수를 호출합니다. 🎜🎜예외 처리🎜🎜두 개의 콜백이 .then
메서드에 전달될 수 있으며 Promise/A+ 사양🎜🎜첫 번째는 fulfilled
의 콜백🎜🎜두 번째는 rejected
의 콜백🎜 🎜🎜🎜🎜 🎜그렇다면 이것의 장점은 무엇인가요? 초기 솔루션보다 더 번거로워 보이죠?- 🎜🎜통합 사양으로 가독성과 확장성을 높일 수 있습니다🎜🎜🎜🎜콜백 지옥을 조금 줄입니다🎜🎜 🎜🎜🎜
🎜2.3 약속 상태🎜
🎜🎜먼저 예를 들어 코드를 현실적인 예로 추상화하겠습니다🎜🎜여자친구에게 약속합니다. 맛있는 음식을 먹으러 가세요 다음 주말 음식 (아직 다음 주말이 아니고 상태는 🎜대기 상태🎜)🎜🎜시간이 빨리 지나서 오늘이 주말이고 여자친구와 바비큐, 디저트, 밀크티를 먹었어요... (🎜현금상태🎜)🎜🎜 시간이 빨리 가네요. 오늘이 주말인데 외출을 하려고 합니다. 아쉽게도 온라인에서 발생한 긴급한 문제를 해결하기 위해 제품 관리자가 회사에 다시 방문해야 합니다. (생활을 위해) 여자 친구를 정중하게 거절하고 이유를 설명할 수 있습니다(🎜거부 상태🎜)🎜🎜🎜🎜이용하세요.promise
, 약속을 하세요. 세 단계로 나눌 수 있습니다🎜🎜pending(보류 중), 실행자가 실행되고, 상태가 여전히 대기 중이고, 이행되지 않았으며, 거부되지 않았습니다🎜 🎜 이행(fulfilled), resolve
함수 실행은 이행 상태를 나타냅니다. 🎜🎜rejected(거부), reject
함수 실행은 거부됨 상태를 나타냅니다 🎜🎜 🎜🎜우선 , 상태가 보류 상태에서 다른 상태로 변경되는 한 상태는 더 이상 변경할 수 없습니다🎜🎜🎜다음 코드를 생각해 보세요.🎜const promise = new Promise((resolve, reject) => { setTimeout(() => { reject('失败') resolve('成功') }, 3000); }) promise.then(res => console.log(res)).catch(err => console.log(err)) //失败
- 当我调用
reject
之后,在调用resolve
是无效的,因为状态已经发生改变,并且是不可逆的。
2.4 resolve不同值的区别
- 如果
resolve
传入一个普通的值或者对象,只能传递接受一个参数,那么这个值会作为then
回调的参数
const promise = new Promise((resolve, reject) => { resolve({name: 'ice', age: 22}) }) promise.then(res => console.log(res)) // {name: 'ice', age: 22}
- 如果
resolve
中传入的是另外一个Promise
,那么这个新Promise
会决定原Promise
的状态
const promise = new Promise((resolve, reject) => { resolve(new Promise((resolve, reject) => { setTimeout(() => { resolve('ice') }, 3000); })) }) promise.then(res => console.log(res)) //3s后 ice
- 如果
resolve
中传入的是一个对象,并且这个对象有实现then
方法,那么会执行该then
方法,then
方法会传入resolve
,reject
函数。此时的promise
状态取决于你调用了resolve
,还是reject
函数。这种模式也称之为: thenable
const promise = new Promise((resolve, reject) => { resolve({ then(res, rej) { res('hi ice') } }) }) promise.then(res => console.log(res)) // hi ice
2.5 Promise的实例方法
- 实例方法,存放在
Promise.prototype
上的方法,也就是Promise的显示原型上,当我new Promise的时候,会把返回的改对象的 promise[[prototype]](隐式原型) === Promise.prototype (显示原型) - 即new返回的对象的隐式原型指向了Promise的显示原型
2.5.1 then方法
2.5.1.1 then的参数
-
then
方法可以接受参数,一个参数为成功的回调,另一个参数为失败的回调,前面重构requestData
中有演练过。
const promise = new Promise((resolve, reject) => { resolve('request success') // reject('request error') }) promise.then(res => console.log(res), rej => console.log(rej)) //request success
- 如果只捕获错误,还可以这样写
- 因为第二个参数是捕获异常的,第一个可以写个
null
或""
占位
- 因为第二个参数是捕获异常的,第一个可以写个
const promise = new Promise((resolve, reject) => { // resolve('request success') reject('request error') }) promise.then(null, rej => console.log(rej)) //request error
2.5.1.2 then的多次调用
const promise = new Promise((resolve, reject) => { resolve('hi ice') }) promise.then(res => ({name:'ice', age:22})) .then(res => console.log(res)) //{name:'ice', age:22}
- 调用多次则会执行多次
2.5.1.3 then的返回值
-
then
方法是有返回值的,它的返回值是promise
,但是是promise
那它的状态如何决定呢?接下来让我们一探究竟。
2.5.1.3.1 返回一个普通值 状态:fulfilled
const promise = new Promise((resolve, reject) => { resolve('hi ice') }) promise.then(res => ({name:'ice', age:22})) .then(res => console.log(res)) //{name:'ice', age:22}
- 返回一个普通值,则相当于主动调用
Promise.resolve
,并且把返回值作为实参传递到then
方法中。 - 如果没有返回值,则相当于返回
undefined
2.5.1.3.2 明确返回一个promise 状态:fulfilled
const promise = new Promise((resolve, reject) => { resolve('hi ice') }) promise.then(res => { return new Promise((resolve, reject) => { resolve('then 的返回值') }) }).then(res => console.log(res)) //then 的返回值
- 主动返回一个
promise
对象,状态和你调用resolve
,还是reject
有关
2.5.1.3.3 返回一个thenable对象 状态:fulfilled
const promise = new Promise((resolve, reject) => { resolve('hi ice') }) promise.then(res => { return { then(resolve, reject) { resolve('hi webice') } } }).then(res => console.log(res)) //hi webice
- 返回了一个thenable对象,其状态取决于你是调用了
resolve
,还是reject
2.5.2 catch方法
2.5.2.1 catch的多次调用
const promise = new Promise((resolve, reject) => { reject('ice error') }) promise.catch(err => console.log(err)) promise.catch(err => console.log(err)) promise.catch(err => console.log(err)) //ice error //ice error //ice error
2.5.2.2 catch的返回值
- catch方法是有返回值的,它的返回值是promise,但是是promise那它的状态如何决定呢?接下来让我们一探究竟。
- 如果返回值明确一个promise或者thenble对象,取决于你调用了
resolve
还是reject
2.5.2.2.1 返回一个普通对象
const promise = new Promise((resolve, reject) => { reject('ice error') }) promise.catch(err => ({name:'ice', age: 22})).then(res => console.log(res)) //{name:'ice', age: 22}
2.5.2.2.2 明确返回一个promise
const promise = new Promise((resolve, reject) => { reject('ice error') }) promise.catch(err => { return new Promise((resolve, reject) => { reject('ice error promise') }) }).catch(res => console.log(res)) //ice error promise
- 此时
new Promise()
调用了reject
函数,则会被catch
捕获到
2.5.2.2.3 返回thenble对象
const promise = new Promise((resolve, reject) => { reject('ice error') }) promise.catch(err => { return { then(resolve, reject) { reject('ice error then') } } }).catch(res => console.log(res)) //ice error then
2.5.3 finally方法
- ES9(2018)新实例方法
- finally(最后),无论promise状态是fulfilled还是rejected都会执行一次
finally
方法
const promise = new Promise((resolve, reject) => { resolve('hi ice') }) promise.then(res => console.log(res)).finally(() => console.log('finally execute')) //finally execute
2.6 Promise中的类方法/静态方法
2.6.1 Promise.reslove
Promise.resolve('ice') //等价于 new Promise((resolve, reject) => resolve('ice'))
- 有的时候,你已经预知了状态的结果为fulfilled,则可以用这种简写方式
2.6.2 Promise.reject
Promise.reject('ice error') //等价于 new Promise((resolve, reject) => reject('ice error'))
- 有的时候,你已经预知了状态的结果为rejected,则可以用这种简写方式
2.6.3 Promise.all
fulfilled 状态
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('hi ice') }, 1000); }) const promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('hi panda') }, 2000); }) const promise3 = new Promise((resolve, reject) => { setTimeout(() => { resolve('hi grizzly') }, 3000); }) Promise.all([promise1, promise2, promise3]).then(res => console.log(res)) //[ 'hi ice', 'hi panda', 'hi grizzly' ]
- all方法的参数传入为一个可迭代对象,返回一个promise,只有三个都为
resolve
状态的时候才会调用.then
方法。 - 只要有一个promise的状态为rejected,则会回调
.catch
方法
rejected状态
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { resolve('hi ice') }, 1000); }) const promise2 = new Promise((resolve, reject) => { setTimeout(() => { reject('hi panda') }, 2000); }) const promise3 = new Promise((resolve, reject) => { setTimeout(() => { resolve('hi grizzly') }, 3000); }) Promise.all([promise1, promise2, promise3]).then(res => console.log(res)).catch(err => console.log(err)) //hi panda
- 当遇到rejectd的时候,后续的promise结果我们是获取不到,并且会把reject的实参,传递给catch的err形参中
2.6.4 Promise.allSettled
- 上面的
Promise.all
有一个缺陷,就是当遇到一个rejected的状态,那么对于后面是resolve
或者reject
的结果我们是拿不到的 - ES11 新增语法
Promise.allSettled
,无论状态是fulfilled/rejected都会把参数返回给我们
所有promise都有结果
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { reject('hi ice') }, 1000); }) const promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('hi panda') }, 2000); }) const promise3 = new Promise((resolve, reject) => { setTimeout(() => { reject('hi grizzly') }, 3000); }) Promise.allSettled([promise1, promise2, promise3]).then(res => console.log(res)) /* [ { status: 'rejected', reason: 'hi ice' }, { status: 'fulfilled', value: 'hi panda' }, { status: 'rejected', reason: 'hi grizzly' } ] */
- 该方法会在所有的Promise都有结果,无论是fulfilled,还是rejected,才会有最终的结果
其中一个promise没有结果
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { reject('hi ice') }, 1000); }) const promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('hi panda') }, 2000); }) const promise3 = new Promise((resolve, reject) => {}) Promise.allSettled([promise1, promise2, promise3]).then(res => console.log(res)) // 什么都不打印
- 其中一个promise没有结果,则什么都结果都拿不到
2.6.5 Promise.race
- race(竞争竞赛)
- 优先获取第一个返回的结果,无论结果是fulfilled还是rejectd
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { reject('hi error') }, 1000); }) const promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('hi panda') }, 2000); }) Promise.race([promise1, promise2]) .then(res => console.log(res)) .catch(e => console.log(e)) //hi error
2.6.6 Promise.any
- 与race类似,只获取第一个状态为fulfilled,如果全部为rejected则报错
AggregateError
const promise1 = new Promise((resolve, reject) => { setTimeout(() => { reject('hi error') }, 1000); }) const promise2 = new Promise((resolve, reject) => { setTimeout(() => { resolve('hi panda') }, 2000); }) Promise.any([promise1, promise2]) .then(res => console.log(res)) .catch(e => console.log(e)) //hi panda
3. Promise的回调地狱 (进阶)
- 我还是以一个需求作为切入点,把知识点嚼碎了,一点一点喂进你们嘴里。
- 当我发送网络请求的时候,需要拿到这次网络请求的数据,再发送网络请求,就这样重复三次,才能拿到我最终的结果。
3.1 卧龙解法
function requestData(url) { return new Promise((resolve, reject) => { setTimeout(() => { if (url.includes('iceweb')) { resolve(url) } else { reject('请求错误') } }, 1000); }) } requestData('iceweb.io').then(res => { requestData(`iceweb.org ${res}`).then(res => { requestData(`iceweb.com ${res}`).then(res => { console.log(res) }) }) }) //iceweb.com iceweb.org iceweb.io
- 虽然能够实现,但是多层代码的嵌套,可读性非常差,我们把这种多层次代码嵌套称之为回调地狱
3.2 凤雏解法
function requestData(url) { return new Promise((resolve, reject) => { setTimeout(() => { if (url.includes('iceweb')) { resolve(url) } else { reject('请求错误') } }, 1000); }) } requestData('iceweb.io').then(res => { return requestData(`iceweb.org ${res}`) }).then(res => { return requestData(`iceweb.com ${res}`) }).then(res => { console.log(res) }) //iceweb.com iceweb.org iceweb.io
- 利用了then链式调用这一特性,返回了一个新的promise,但是不够优雅,思考一下能不能写成同步的方式呢?
3.3 生成器+Promise解法
function requestData(url) { return new Promise((resolve, reject) => { setTimeout(() => { if (url.includes('iceweb')) { resolve(url) } else { reject('请求错误') } }, 1000); }) } function* getData(url) { const res1 = yield requestData(url) const res2 = yield requestData(res1) const res3 = yield requestData(res2) console.log(res3) } const generator = getData('iceweb.io') generator.next().value.then(res1 => { generator.next(`iceweb.org ${res1}`).value.then(res2 => { generator.next(`iceweb.com ${res2}`).value.then(res3 => { generator.next(res3) }) }) }) //iceweb.com iceweb.org iceweb.io
- 大家可以发现我们的
getData
已经变为同步的形式,可以拿到我最终的结果了。那么很多同学会问,generator一直调用.next
不是也产生了回调地狱吗? - 其实不用关心这个,我们可以发现它这个是有规律的,我们可以封装成一个自动化执行的函数,我们就不用关心内部是如何调用的了。
3.4 自动化执行函数封装
function requestData(url) { return new Promise((resolve, reject) => { setTimeout(() => { if (url.includes('iceweb')) { resolve(url) } else { reject('请求错误') } }, 1000); }) } function* getData() { const res1 = yield requestData('iceweb.io') const res2 = yield requestData(`iceweb.org ${res1}`) const res3 = yield requestData(`iceweb.com ${res2}`) console.log(res3) } //自动化执行 async await相当于自动帮我们执行.next function asyncAutomation(genFn) { const generator = genFn() const _automation = (result) => { let nextData = generator.next(result) if(nextData.done) return nextData.value.then(res => { _automation(res) }) } _automation() } asyncAutomation(getData) //iceweb.com iceweb.org iceweb.io
- 利用promise+生成器的方式变相实现解决回调地狱问题,其实就是
async await
的一个变种而已 - 最早为TJ实现,前端大神人物
- async await核心代码就类似这些,内部主动帮我们调用
.next
方法
3.5 最终解决回调地狱的办法
function requestData(url) { return new Promise((resolve, reject) => { setTimeout(() => { if (url.includes('iceweb')) { resolve(url) } else { reject('请求错误') } }, 1000); }) } async function getData() { const res1 = await requestData('iceweb.io') const res2 = await requestData(`iceweb.org ${res1}`) const res3 = await requestData(`iceweb.com ${res2}`) console.log(res3) } getData() //iceweb.com iceweb.org iceweb.io
- 你会惊奇的发现,只要把
getData
生成器函数函数,改为async
函数,yeild
的关键字替换为await
就可以实现异步代码同步写法了。
4. async/await 剖析
- async(异步的)
- async 用于申明一个异步函数
4.1 async内部代码同步执行
- 异步函数的内部代码执行过程和普通的函数是一致的,默认情况下也是会被同步执行
async function sayHi() { console.log('hi ice') } sayHi() //hi ice
4.2 异步函数的返回值
-
异步函数的返回值和普通返回值有所区别
- 普通函数主动返回什么就返回什么,不返回为
undefined
- 异步函数的返回值特点
- 明确有返回一个普通值,相当于
Promise.resolve
(返回值) - 返回一个thenble对象则由,then方法中的
resolve
,或者reject
有关 - 明确返回一个promise,则由这个promise决定
- 明确有返回一个普通值,相当于
- 普通函数主动返回什么就返回什么,不返回为
异步函数中可以使用
await
关键字,现在在全局也可以进行await
,但是不推荐。会阻塞主进程的代码执行
4.3 异步函数的异常处理
- 如果函数内部中途发生错误,可以通过try catch的方式捕获异常
- 如果函数内部中途发生错误,也可以通过函数的返回值.catch进行捕获
async function sayHi() { console.log(res) } sayHi().catch(e => console.log(e)) //或者 async function sayHi() { try { console.log(res) }catch(e) { console.log(e) } } sayHi() //ReferenceError: res is not defined
4.4 await 关键字
- 异步函数中可以使用
await
关键字,普通函数不行 - await特点
- 通常await关键字后面都是跟一个Promise
- 可以是普通值
- 可以是thenble
- 可以是Promise主动调用
resolve或者reject
- 这个promise状态变为fulfilled才会执行
await
后续的代码,所以await
后面的代码,相当于包括在.then
方法的回调中,如果状态变为rejected,你则需要在函数内部try catch
,或者进行链式调用进行.catch
操作
- 通常await关键字后面都是跟一个Promise
function requestData(url) { return new Promise((resolve, reject) => { setTimeout(() => { if (url.includes('iceweb')) { resolve(url) } else { reject('请求错误') } }, 1000); }) } async function getData() { const res = await requestData('iceweb.io') console.log(res) } getData() // iceweb.io
5. 结语
- 如果现在真的看不到未来是怎样,你就不如一直往前走,不知道什么时候天亮,去奔跑就好,跑着跑着天就亮了。
【相关推荐:javascript视频教程、编程基础视频】

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











WebSocket 및 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법 소개: 지속적인 기술 개발로 음성 인식 기술은 인공 지능 분야의 중요한 부분이 되었습니다. WebSocket과 JavaScript를 기반으로 한 온라인 음성 인식 시스템은 낮은 대기 시간, 실시간, 크로스 플랫폼이라는 특징을 갖고 있으며 널리 사용되는 솔루션이 되었습니다. 이 기사에서는 WebSocket과 JavaScript를 사용하여 온라인 음성 인식 시스템을 구현하는 방법을 소개합니다.

WebSocket과 JavaScript: 실시간 모니터링 시스템 구현을 위한 핵심 기술 서론: 인터넷 기술의 급속한 발전과 함께 실시간 모니터링 시스템이 다양한 분야에서 널리 활용되고 있다. 실시간 모니터링을 구현하는 핵심 기술 중 하나는 WebSocket과 JavaScript의 조합입니다. 이 기사에서는 실시간 모니터링 시스템에서 WebSocket 및 JavaScript의 적용을 소개하고 코드 예제를 제공하며 구현 원칙을 자세히 설명합니다. 1. 웹소켓 기술

JavaScript 및 WebSocket을 사용하여 실시간 온라인 주문 시스템을 구현하는 방법 소개: 인터넷의 대중화와 기술의 발전으로 점점 더 많은 레스토랑에서 온라인 주문 서비스를 제공하기 시작했습니다. 실시간 온라인 주문 시스템을 구현하기 위해 JavaScript 및 WebSocket 기술을 사용할 수 있습니다. WebSocket은 TCP 프로토콜을 기반으로 하는 전이중 통신 프로토콜로 클라이언트와 서버 간의 실시간 양방향 통신을 실현할 수 있습니다. 실시간 온라인 주문 시스템에서는 사용자가 요리를 선택하고 주문을 하면

WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법 오늘날의 디지털 시대에는 점점 더 많은 기업과 서비스에서 온라인 예약 기능을 제공해야 합니다. 효율적인 실시간 온라인 예약 시스템을 구현하는 것이 중요합니다. 이 기사에서는 WebSocket과 JavaScript를 사용하여 온라인 예약 시스템을 구현하는 방법을 소개하고 구체적인 코드 예제를 제공합니다. 1. WebSocket이란 무엇입니까? WebSocket은 단일 TCP 연결의 전이중 방식입니다.

일상생활에서 우리는 약속과 이행 사이에서 종종 문제에 직면합니다. 개인적인 관계에서든 비즈니스 거래에서든 약속을 이행하는 것은 신뢰 구축의 핵심입니다. 그러나 헌신의 장단점은 종종 논란의 여지가 있습니다. 이 기사에서는 약속의 장단점을 살펴보고 약속을 지키는 방법에 대한 몇 가지 조언을 제공합니다. 약속된 혜택은 분명합니다. 첫째, 헌신은 신뢰를 구축합니다. 사람이 약속을 지키면 다른 사람들이 자신을 믿을 만한 사람이라고 믿게 만듭니다. 신뢰는 사람들 사이에 확립된 유대이며, 이는 사람들을 더 나은 사람으로 만들 수 있습니다.

JavaScript 및 WebSocket: 효율적인 실시간 일기 예보 시스템 구축 소개: 오늘날 일기 예보의 정확성은 일상 생활과 의사 결정에 매우 중요합니다. 기술이 발전함에 따라 우리는 날씨 데이터를 실시간으로 획득함으로써 보다 정확하고 신뢰할 수 있는 일기예보를 제공할 수 있습니다. 이 기사에서는 JavaScript 및 WebSocket 기술을 사용하여 효율적인 실시간 일기 예보 시스템을 구축하는 방법을 알아봅니다. 이 문서에서는 특정 코드 예제를 통해 구현 프로세스를 보여줍니다. 우리

JavaScript 튜토리얼: HTTP 상태 코드를 얻는 방법, 특정 코드 예제가 필요합니다. 서문: 웹 개발에서는 서버와의 데이터 상호 작용이 종종 포함됩니다. 서버와 통신할 때 반환된 HTTP 상태 코드를 가져와서 작업의 성공 여부를 확인하고 다양한 상태 코드에 따라 해당 처리를 수행해야 하는 경우가 많습니다. 이 기사에서는 JavaScript를 사용하여 HTTP 상태 코드를 얻는 방법과 몇 가지 실용적인 코드 예제를 제공합니다. XMLHttpRequest 사용

Promise.resolve()에 대한 자세한 설명에는 특정 코드 예제가 필요합니다. Promise는 비동기 작업을 처리하기 위한 JavaScript의 메커니즘입니다. 실제 개발에서는 순서대로 실행해야 하는 일부 비동기 작업을 처리해야 하는 경우가 종종 있으며, 이행된 Promise 객체를 반환하기 위해 Promise.resolve() 메서드가 사용됩니다. Promise.resolve()는 Promise 클래스의 정적 메서드입니다.