忘記文檔密碼怎么找回來
738
2022-05-30
術(shù)語
1. Promise
promise 是一個(gè)擁有 then 方法的 object 或 function ,其行為符合本規(guī)范
2. thenable
是一個(gè)定義了 then 方法的 object 或 function
3. 值(value)
指任何 JavaScript 的合法值(包括 undefined , thenable 和 promise);
4. 異常(exception)
通過throw拋出一個(gè)值
5. 原因(reason)
一個(gè)promise被拒絕的原因
class Promise { constructor(executor) { this.value = undefined; this.reason = undefined; } } function Promise(){} Promise.prototype.then=function(){}
要求
1. Promise 的狀態(tài)
當(dāng)前Promise的狀態(tài)只能是下面三種狀態(tài)中的一種,不能存在多種狀態(tài)。
示例:
const STATUS_PENDING = "pending"; const STATUS_FULFILLED = "fulfilled"; const STATUS_REJECTED = "rejected"; class Promise { constructor(executor) { this.status = STATUS_PENDING; } }
處于等待時(shí),狀態(tài)可以遷移至執(zhí)行態(tài)或拒絕態(tài)
處于執(zhí)行時(shí):
不能遷移至其他任何狀態(tài)
必須擁有一個(gè)不可變的終值
處于拒絕時(shí):
不能遷移至其他任何狀態(tài)
必須擁有一個(gè)不可變的reason
這里的不可變指的是恒等(即可用 === 判斷相等),引用數(shù)據(jù)類型只要保證地址相等即可。
new Promise((resolve, reject) => { resolve('成功'); reject('拒絕') }).then((res) => { console.log(res,"res") }, (error) => { console.log(error,'reason') }) new Promise()時(shí)狀態(tài)是pending, 當(dāng)程序執(zhí)行,也就是(resolve, reject) => { resolve('成功'); reject('拒絕') },這個(gè)執(zhí)行 這里resolve把值進(jìn)行了this.value = "成功";,但是并不會(huì)this.reason='拒絕', 這是因?yàn)橹挥谐霈F(xiàn)了執(zhí)行就不會(huì)出現(xiàn)拒絕,最后輸出的結(jié)果是"成功 res", 如果注釋掉resolve('成功');,最后輸出的結(jié)果是 "拒絕 reason"。
2. Then 方法
一個(gè) promise 必須提供一個(gè) then 方法以訪問其當(dāng)前值、終值 和 reason。
promise 的 then 方法接受兩個(gè)函數(shù)參數(shù):
promise.then(onFulfilled, onRejected) then((res) => { console.log(res,"res") }, (error) => { console.log(error,'reason') })
如果 onFulfilled 不是函數(shù),必須被忽略
如果 onRejected 不是函數(shù),必須被忽略
如果 onFulfilled 是函數(shù):
當(dāng) promise 執(zhí)行結(jié)束后其必須被調(diào)用,其第一個(gè)參數(shù)為 promise的value
在 promise 執(zhí)行結(jié)束前其不可被調(diào)用
其調(diào)用次數(shù)不可超過一次
new Promise((resolve, reject) => { resolve(123) }).then(result => { console.log(result); }, error => { console.log(error); }); // 這里resolve執(zhí)行結(jié)束才會(huì)執(zhí)行then,這里的result就是終值
如果 onRejected 是函數(shù):
當(dāng) promise 被拒絕執(zhí)行后其必須被調(diào)用,其第一個(gè)參數(shù)為 promise 的reason
在 promise 被拒絕執(zhí)行前其不可被調(diào)用
其調(diào)用次數(shù)不可超過一次
onFulfilled 和 onRejected 只有在執(zhí)行環(huán)境堆棧僅包含平臺(tái)代碼時(shí)才可被調(diào)用 >> 注1
onFulfilled 和 onRejected 必須被作為函數(shù)調(diào)用(即沒有 this 值)>> 注2
then方法可以被同一個(gè)promise 調(diào)用多次
當(dāng) promise 成功執(zhí)行時(shí),所有 onFulfilled 需按照其注冊(cè)順序依次回調(diào)
當(dāng) promise 被拒絕執(zhí)行時(shí),所有的 onRejected 需按照其注冊(cè)順序依次回調(diào)
new Promise.then().then()
then 方法必須返回一個(gè) promise 對(duì)象 >> 注3, 這也就是then可以被多次調(diào)用的原因。
Promise.prototype.then=function(onFulfilled, onRejected){ return new Promise() } promise2 = promise1.then(onFulfilled, onRejected);
如果 onFulfilled 或者 onRejected 返回一個(gè)值 x ,則運(yùn)行下面的 Promise 解決過程:[[Resolve]](promise2, x)
promise1.then((value)=>{ return x; }, (reason)=>{ return x }), // 這種情況需要處理x函數(shù)還是值還是其他情況 ,所有用到了 Promise 解決過程 // 這種情況直接 Promise.prototype.then=function(onFulfilled, onRejected){ return let promise2 = new Promise((resolve,reject)=>{ try { let x = onFulfilled(this.value); resolvePromise(promise2, x, resolve, reject); } catch (e) { reject(e); } }) }
如果 onFulfilled 或者 onRejected 拋出一個(gè)異常 e ,則 promise2 必須拒絕執(zhí)行,并返回拒因 e
promise1.then((value)=>{ throw new Error() }, (reason)=>{ throw new Error() }), // 這種情況直接 Promise.prototype.then=function(onFulfilled, onRejected){ return new Promise((resolve,reject)=>{ try { // console.log("執(zhí)行 onFulfilled"); // 這里的x是啥? 是then中回調(diào)的return的返回值 onFulfilled(this.value); 或者 onReject(this.reason) } catch (e) { reject(e); } }) }
如果 onFulfilled 不是函數(shù)且 promise1 成功執(zhí)行, promise2 必須成功執(zhí)行并返回相同的值
promise1.then(1,2), Promise.prototype.then=function(onFulfilled, onRejected){ if (this.status === STATUS_FULFILLED) { return new Promise((resolve,reject)=>{ if(typeof onFulfilled !== "function" ){ resolve(onFulfilled) } if(typeof onRejected !== "function" ){ resolve(onRejected) } }) } }
如果 onRejected 不是函數(shù)且 promise1 拒絕執(zhí)行, promise2 必須拒絕執(zhí)行并返回相同的reason
promise1.then(1,2), Promise.prototype.then=function(onFulfilled, onRejected){ if (this.status === STATUS_PENDING) { return new Promise((resolve,reject)=>{ reject(onRejected) }) } }
Promise 解決過程
Promise 解決過程是需要輸入一個(gè) promise 和一個(gè)值 x 的一個(gè)抽象的操作,稱為 [[Resolve]](promise, x),如果 x 有 then 方法且看上去像一個(gè) Promise ,解決程序即嘗試使 promise 接受 x 的狀態(tài);否則其用 x 的值來執(zhí)行 promise 。(x是返回值,請(qǐng)注意上面的例子)
解決過程步驟:
x 與 promise 相等
如果 promise 和 x 指向同一對(duì)象,直接 throw new TypeError
let p1=new Promise(resolve=>{ resolve() }) let p2=p1.then(data=>{ // 返回了p2 return p2 })
x 是Promise
如果 x 是一個(gè) Promise ,則使 promise 接受 x 的狀態(tài) >>注4:
如果 x 處于等待, promise 需保持等待直至 x 被執(zhí)行或拒絕
如果 x 處于執(zhí)行,用相同的值執(zhí)行 promise
如果 x 處于拒絕,用相同的reason拒絕 promise
x 為對(duì)象或函數(shù)
如果 x 為對(duì)象或者函數(shù):
把 x.then 賦值給 then>> 注5
如果取 x.then 的值時(shí)拋出錯(cuò)誤 e ,則以 e 為reason拒絕 promise
如果then是函數(shù),將x作為函數(shù)的作用域this調(diào)用。傳遞兩個(gè)回調(diào)函數(shù)作為參數(shù),第一個(gè)參數(shù)叫做resolvePromise
,第二個(gè)參數(shù)叫做rejectPromise:
如果 resolvePromise 以值 y 為參數(shù)被調(diào)用,則運(yùn)行 [[Resolve]](promise, y)
如果 rejectPromise 以reason r 為參數(shù)被調(diào)用,則以reason r 拒絕 promise
如果 resolvePromise 和 rejectPromise 均被調(diào)用,或者被同一參數(shù)調(diào)用了多次,則優(yōu)先采用首次調(diào)用并忽略剩下的調(diào)用
如果調(diào)用then方法拋出了異常e:
如果 resolvePromise 或 rejectPromise 已經(jīng)被調(diào)用,則忽略之
否則以 e 為reason拒絕 promise
如果 then 不是函數(shù),以 x 為參數(shù)執(zhí)行 promise
如果 x 不為對(duì)象或者函數(shù),以 x 為參數(shù)執(zhí)行 promise
function resolvePromise(promise2, x, resolve, reject) { // 用來保存是否已經(jīng)reject或者resolve過 let called if (promise2 === x) { throw new TypeError('Chaining cycle detected for promise') } // 如果是函數(shù)或者object的話先默認(rèn)是promise if (x != null && (typeof x === 'object' || typeof x === 'function')) { try { let then = x.then // 如果then是函數(shù)的話 if (typeof then === 'function') { // 為啥不直接x.then() // 因?yàn)閠hen已經(jīng)判斷過是不是function,但是x.then沒有判斷過 // 就讓then執(zhí)行 第一個(gè)參數(shù)是this 后面是成功的回調(diào) 和 失敗的回調(diào) // 這里的y是啥,如果x是promsie的話,那么y就是x中的resolve/reject的值 then.call(x, y => { // 成功和失敗只能調(diào)用一個(gè) if (called) return; called = true; // resolve的結(jié)果依舊是promise 那就繼續(xù)解析 resolvePromise(promise2, y, resolve, reject); }, err => { // 成功和失敗只能調(diào)用一個(gè) if (called) return; called = true; reject(err); }) } else { resolve(x); // 如果不是函數(shù),那就直接返回結(jié)果 } } catch (error) { // 成功和失敗只能調(diào)用一個(gè) if (called) return; called = true; // 沒有then 不是函數(shù)也不是普通值 reject(error) } } else { // x 是一個(gè)普通值 resolve(x) } }
如果一個(gè) promise 被一個(gè)循環(huán)的 thenable 鏈中的對(duì)象解決,而 [[Resolve]](promise, thenable) 的遞歸性質(zhì)又使得其被再次調(diào)用,根據(jù)上述的算法將會(huì)陷入無限遞歸之中。算法雖不強(qiáng)制要求,但也鼓勵(lì)施者檢測(cè)這樣的遞歸是否存在,若檢測(cè)到存在則以一個(gè)可識(shí)別的 TypeError 為reason來拒絕 promise >>注6。
注釋
注1 這里的平臺(tái)代碼指的是引擎、環(huán)境以及 promise 的實(shí)施代碼。實(shí)踐中要確保 onFulfilled 和 onRejected 方法異步執(zhí)行,且應(yīng)該在 then 方法被調(diào)用的那一輪事件循環(huán)之后的新執(zhí)行棧中執(zhí)行。這個(gè)事件隊(duì)列可以采用“宏任務(wù)(macro-task)”機(jī)制或者“微任務(wù)(micro-task)”機(jī)制來實(shí)現(xiàn)。由于 promise 的實(shí)施代碼本身就是平臺(tái)代碼(**譯者注:**即都是 JavaScript),故代碼自身在處理在處理程序時(shí)可能已經(jīng)包含一個(gè)任務(wù)調(diào)度隊(duì)列。
注2 也就是說在**嚴(yán)格模式(strict)**中,函數(shù) this 的值為 undefined ;在非嚴(yán)格模式中其為全局對(duì)象。
注3 代碼實(shí)現(xiàn)在滿足所有要求的情況下可以允許 promise2 === promise1 。每個(gè)實(shí)現(xiàn)都要文檔說明其是否允許以及在何種條件下允許 promise2 === promise1 。
注4 總體來說,如果 x 符合當(dāng)前實(shí)現(xiàn),我們才認(rèn)為它是真正的 promise 。這一規(guī)則允許那些特例實(shí)現(xiàn)接受符合已知要求的 Promises 狀態(tài)。
注5 這里我們存儲(chǔ)了x.then的引用 ,然后在if中進(jìn)行判斷,并且可以避免多次訪問 x.then 屬性。同時(shí)這確保了該屬性的一致性,因?yàn)槠渲悼赡茉跈z索調(diào)用時(shí)被改變。
注6 實(shí)現(xiàn)不應(yīng)該對(duì) thenable 鏈的深度設(shè)限,并假定超出本限制的遞歸就是無限循環(huán)。只有真正的循環(huán)遞歸才應(yīng)能導(dǎo)致 TypeError 異常;如果一條無限長的鏈上 thenable 均不相同,那么遞歸下去永遠(yuǎn)是正確的行為。
Promise
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。