오늘은 Promise를 공유하겠습니다. 저자는 초기 비동기 코드의 딜레마, Promise의 출현으로 어떤 문제가 해결되었는지, 비동기 콜백 지옥에 대한 궁극적인 해결책, 실제로 Async Wait의 핵심 구문을 구현해 보겠습니다. , async/await는 Generator+promise의 변형일 뿐입니다.
promise
를 더 잘 이해할 수 있습니다. promise
。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
。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))
Promise
(承诺),给予调用者一个承诺,过一会返回数据给你,就可以创建一个promise对象new
一个promise
,此时我们需要传递一个回调函数,这个函数为立即执行的,称之为(executor)reslove
,reject
(函数可以进行传参)reslove
函数,会回调promise对象的.then函数reject
函数,会回调promise对象的.catche函数new Promise((resolve, reject) => { console.log(`executor 立即执行`) })
executor
是立即执行的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))
executor
(会被Promise类中自动执行)resolve
函数,失败的时候调用reject
函数,把需要的参数传递出去。.then
方法中可以传入两个回调,您也可以查看Promise/A+规范fulfilled
的回调rejected
的回调统一规范,可以增强阅读性和扩展性
小幅度减少回调地狱
promise
的时候,给它一个承诺,我们可以将他划分为三个阶段resolve
函数则代表了已兑现状态reject
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
은 성공하거나 실패하더라도 반환되지 않습니다. 비동기 작업은 제쳐두고, 내부에는 반환 값이 없으므로 값이 정의되지 않음
입니다. 🎜🎜🎜🎜const promise = new Promise((resolve, reject) => { resolve({name: 'ice', age: 22}) }) promise.then(res => console.log(res)) // {name: 'ice', age: 22}🎜🎜초기 해결 방법은 실패 콜백과 성공 콜백 두 개를 전달하는 것이었습니다. 그러면 많은 개발자들이 '이거 대단하지 않나요?'라고 묻습니다. js의 함수는 일급 시민이므로 전달할 수 있지만 너무 유연하고 사양이 없습니다. 🎜🎜프레임워크를 사용하는 경우 실제 매개변수를 실패한 순서대로 올바르게 전달하려면 프레임워크 소스 코드도 읽어야 합니다. 매개변수가 잘못된 순서로 전달되면 매우 위험합니다. 🎜🎜
Promise
(약속), 호출자에게 약속을 하고 잠시 후 데이터를 반환합니다. Promise 개체🎜🎜promise
를 새
할 때 콜백 함수를 전달해야 합니다. 이 함수는 즉시 실행되고 (executor)🎜🎜 호출됩니다. , 콜백 함수에 reslove
, reject
라는 두 개의 매개변수를 전달해야 합니다(함수는 매개변수를 전달할 수 있음)🎜🎜reslove
가 실행될 때 > 함수는 Promise 개체의 .then 함수를 호출합니다🎜🎜reject
함수가 실행되면 Promise 개체의 .catche 함수가 다시 호출됩니다🎜🎜🎜🎜const promise = new Promise((resolve, reject) => { resolve(new Promise((resolve, reject) => { setTimeout(() => { resolve('ice') }, 3000); })) }) promise.then(res => console.log(res)) //3s后 ice🎜🎜들어오는
executor
가 즉시 실행됩니다🎜🎜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
의 콜백🎜 🎜🎜🎜🎜 🎜그렇다면 이것의 장점은 무엇인가요? 초기 솔루션보다 더 번거로워 보이죠?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
是无效的,因为状态已经发生改变,并且是不可逆的。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
Promise.prototype
上的方法,也就是Promise的显示原型上,当我new Promise的时候,会把返回的改对象的 promise[[prototype]](隐式原型) === Promise.prototype (显示原型)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
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}
then
方法是有返回值的,它的返回值是promise
,但是是promise
那它的状态如何决定呢?接下来让我们一探究竟。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
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
有关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
resolve
,还是reject
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
resolve
还是reject
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}
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
捕获到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
finally
方法const promise = new Promise((resolve, reject) => { resolve('hi ice') }) promise.then(res => console.log(res)).finally(() => console.log('finally execute')) //finally execute
Promise.resolve('ice') //等价于 new Promise((resolve, reject) => resolve('ice'))
Promise.reject('ice error') //等价于 new Promise((resolve, reject) => reject('ice error'))
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' ]
resolve
状态的时候才会调用.then
方法。.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
Promise.all
有一个缺陷,就是当遇到一个rejected的状态,那么对于后面是resolve
或者reject
的结果我们是拿不到的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没有结果
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)) // 什么都不打印
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
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
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
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
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
不是也产生了回调地狱吗?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
async await
的一个变种而已.next
方法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
就可以实现异步代码同步写法了。async function sayHi() { console.log('hi ice') } sayHi() //hi ice
异步函数的返回值和普通返回值有所区别
undefined
Promise.resolve
(返回值)resolve
,或者reject
有关异步函数中可以使用await
关键字,现在在全局也可以进行await
,但是不推荐。会阻塞主进程的代码执行
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
await
关键字,普通函数不行resolve或者reject
await
后续的代码,所以await
后面的代码,相当于包括在.then
方法的回调中,如果状态变为rejected,你则需要在函数内部try catch
,或者进行链式调用进行.catch
操作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
【相关推荐:javascript视频教程、编程基础视频】