Heute werde ich Versprechen mit Ihnen teilen. Der Autor wird mit dem Dilemma des frühen asynchronen Codes beginnen, welche Probleme die Entstehung von Versprechen löst, die ultimative Lösung für die asynchrone Rückrufhölle und die Implementierung der Kernsyntax von Async /await ist nur eine Variante von generator+promise .
promise
besser verstehen. 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)) //失败🎜🎜Zuallererst müssen Sie stattdessen die Ausführungsreihenfolge des
js
-Codes verstehen es als selbstverständlich zu betrachten, ist der Code tatsächlich nicht. Befolgen Sie die Reihenfolge, die Sie geschrieben haben. 🎜🎜Warum ist es also undefiniert
? 🎜🎜Zuallererst beginne ich mit der Ausführung der Funktion, wenn ich die Funktion requestData
ausführe. Wenn ein asynchroner Vorgang auftritt, wird die Ausführung des folgenden Codes nicht blockiert, da js ein Single-Thread-Vorgang ist, sodass der von Ihnen geschriebene return
nicht zurückgegeben wird, wenn er erfolgreich ist oder fehlschlägt. Dann gilt in dieser Funktion: Ich habe die asynchrone Operation beiseite gelegt. Es gibt keinen Rückgabewert, daher ist der Wert undefiniert
. 🎜🎜🎜🎜const promise = new Promise((resolve, reject) => { resolve({name: 'ice', age: 22}) }) promise.then(res => console.log(res)) // {name: 'ice', age: 22}🎜🎜Die erste Lösung bestand darin, zwei Rückrufe einzugeben, einen für Misserfolg und einen für Erfolg. Dann werden sich viele Entwickler fragen: Ist das nicht großartig? Es ist ganz einfach. Funktionen in js sind erstklassige Bürger und können weitergegeben werden, aber das ist zu flexibel und hat keine Spezifikationen. 🎜🎜Wenn Sie ein Framework verwenden, sollten Sie auch den Quellcode des Frameworks lesen und die tatsächlichen Parameter in der fehlgeschlagenen Reihenfolge korrekt übergeben. Es ist sehr gefährlich, wenn die Parameter in der falschen Reihenfolge übergeben werden. 🎜🎜
Versprechen
(Versprechen), geben Sie dem Anrufer ein Versprechen und geben Sie die Daten nach einer Weile an Sie zurück ein Versprechensobjekt🎜🎜Wenn wir ein Versprechen
neu
, müssen wir eine Rückruffunktion übergeben. Diese Funktion wird sofort ausgeführt und heißt (Executor)🎜🎜 Für diese Rückruffunktion , müssen wir zwei Parameter an die Rückruffunktion übergeben, reslove
, reject
(die Funktion kann Parameter übergeben)🎜🎜Wenn reslove
ausgeführt wird > Die Funktion ruft die .then-Funktion des Promise-Objekts zurück🎜🎜Wenn die Funktion reject
ausgeführt wird, wird die .catche-Funktion des Promise-Objekts zurückgerufen🎜🎜🎜🎜const promise = new Promise((resolve, reject) => { resolve(new Promise((resolve, reject) => { setTimeout(() => { resolve('ice') }, 3000); })) }) promise.then(res => console.log(res)) //3s后 ice🎜🎜Der eingehende
executor
wird sofort ausgeführt🎜🎜const promise = new Promise((resolve, reject) => { resolve({ then(res, rej) { res('hi ice') } }) }) promise.then(res => console.log(res)) // hi ice🎜🎜Wenn in der Funktion diese Klasse neu ist, heißt die übergebene Rückruffunktion
executor
(sie wird automatisch in der Promise-Klasse ausgeführt)🎜🎜Rufen Sie auf zum richtigen Zeitpunkt Die Funktion „resolve
ruft die Funktion „reject“ auf, wenn sie fehlschlägt, und übergibt die erforderlichen Parameter. 🎜🎜Ausnahmebehandlung🎜🎜Zwei Rückrufe können in der .then
-Methode übergeben werden, Sie können auch Promise/A+ Spezifikation🎜🎜Der erste ist der Rückruf von erfüllt
🎜🎜Der zweite ist der Rückruf von abgelehnt
🎜 🎜🎜🎜🎜 🎜Was sind dann die Vorteile davon? Erscheint es umständlicher als die frühen Lösungen?promise
, geben Sie ihm ein Versprechen, wir können es in drei Phasen unterteilen🎜🎜pending (ausstehend), der Executor wird ausgeführt, der Status wartet noch, wurde nicht eingehalten und wurde nicht abgelehnt🎜 🎜 erfüllt (erfüllt), die Ausführung der Funktion resolve
stellt den Status „erfüllt“ dar 🎜🎜abgelehnt (abgelehnt), die Ausführung der Funktion reject
stellt den Status „abgelehnt“ dar 🎜🎜 🎜🎜Zuallererst , solange sich der Status vom Status „Ausstehend“ in einen anderen Status ändert, kann der Status nicht mehr geändert werden🎜🎜🎜Denken Sie an den folgenden Code:🎜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视频教程、编程基础视频】