promise的注意點:
1.狀態(tài)不可變
2.值穿透糠雨,then
的回調(diào)resolve
要是不是一個function
而是基本類型吉执,那么這個基本類型就會傳遞給下一個then
關(guān)于promise的一道面試題
3.then
的回調(diào)resolve
中throw erro
會跳到下一個then
回調(diào)的reject
中
高階函數(shù):接收函數(shù)作為參數(shù)的函數(shù)
1.一個最簡單的高階函數(shù):
function add(x, y, f) {//add為高階函數(shù)
return f(x) + f(y);
}
2.高階函數(shù)決定了回調(diào)的調(diào)用時間以及接收的參數(shù)
例如:高階函數(shù)fn
接收函數(shù)callBack作為參數(shù),就決定了callBack的調(diào)用時間以及callBack的參數(shù)
調(diào)用fn時定義callBack
function fn(callBack) {//定義一個有回調(diào)的function——》fn
//fn決定何時調(diào)用這個回調(diào)挟伙,以及對回調(diào)的傳參
callBack(1,2)
}
fn(function (fir,sec) {//調(diào)用fn傳入回調(diào),決定回調(diào)拿到傳參的具體執(zhí)行
return fir+sec
})
3.高階函數(shù)的回調(diào)接收的參數(shù)仍然是函數(shù)
例如:
定義高階函數(shù)fn,并且給fn的回調(diào)傳入函數(shù)
調(diào)用fn時決定回調(diào)的具體內(nèi)容,以及何時使用fn給的函數(shù)參數(shù)resolve仓蛆、reject
function fn(callBack) {//定義一個有回調(diào)的function——》fn
//fn決定何時調(diào)用這個回調(diào),以及對回調(diào)的傳參
let resolve=function(){
console.log('resolve')
}
let reject=function(){
console.log('reject')
}
callBack(resolve,reject)//對回調(diào)callBack的傳參為函數(shù)
}
fn(function (resolve,reject) {//調(diào)用fn傳入回調(diào)蝌诡,決定回調(diào)拿到傳參的具體執(zhí)行
return resolve()//回調(diào)的定義中決定什么時候使用收到的傳參
})
Promise架構(gòu):
1.new Promise().then()
? 高階函數(shù)的使用:
new MyPromise(handle)
的回調(diào)——>handles收到的參數(shù)為函數(shù)
new MyPromise
會執(zhí)行calss MyPromise
的構(gòu)造函數(shù),所以class MyPromise是在定義高階函數(shù)溉贿,并且回調(diào)接收到的參數(shù)也就是函數(shù)(resolve、reject
)浦旱。
class MyPromise{//定義
constructor(handle){
handle(this.res,this.rej)
}
res(){}
rej(){}
}
new MyPromise(function (resolve,reject) {//使用
resolve(1)
}).then()
new MyPromise().then()
表示執(zhí)行MyPromise
的構(gòu)造函數(shù)之后立馬執(zhí)行then()
then根據(jù)MyPromise實例使用的是resolve()還是reject()來選擇回調(diào)
所以resolve(),reject
改變MyPromise
中的this.state
宇色,then再根據(jù)this.state
選擇執(zhí)行resolve
還是reject
此步驟完成代碼如下:
const PENDING = 'PENDING'//進行中
const FULFILLED = 'FULFILLED'//已成功
const REJECTED = 'REJECTED' //已失敗
class MyPromise{
constructor(handle){
this._value = null
this._status = PENDING
handle(this._resolve.bind(this),this._reject.bind(this))
}
_resolve(val){
if (this._status !== PENDING) return//狀態(tài)不可逆,只能從PENDING——》FULFILLED颁湖,不能從別的狀態(tài)到FULFILLED
this._value=val
this._status=FULFILLED
}
_reject(val){
if (this._status !== PENDING) return//狀態(tài)不可逆宣蠕,只能從PENDING——》REJECTED,不能從別的狀態(tài)到REJECTED
this._value= val
this._status=REJECTED
}
}
MyPromise.prototype.then=function (onFulfilled,onRejected) {
switch (this._status) {
case PENDING:break;
case FULFILLED:onFulfilled(this._value);break;
case REJECTED:onRejected(this._value);break;
}
}
new MyPromise(function (resolve,reject) {
resolve('call resolve')
}).then(function (val) {
console.log(val)
})//call resolve
new MyPromise(function (resolve,reject) {
reject('call reject')
}).then(function () {},function (val) {
console.log(val)
})//call reject
? 注意:1. 高階函數(shù)對this的處理:handle(this._resolve.bind(this),this._reject.bind(this))
傳遞_resolve
與_reject
給handle
調(diào)用甥捺,那么它們的this
會隨著hangle
走抢蚀,所以此處應(yīng)該要bind
? 2.Promise的狀態(tài)不可變:由于只有_resolve
與_reject
會修改狀態(tài),所以只要保證_resolve
镰禾、_reject
修改狀態(tài)前狀態(tài)都為PENDING
就可以做到狀態(tài)不可變
?
2.異步操作
? new MyPromise(handle1).then(handle1)
是同步的皿曲,handle1
執(zhí)行之后會立刻執(zhí)行then()
,異步操作到任務(wù)隊列中等待執(zhí)行。但此時handle1
的異步操作還沒有執(zhí)行羡微,沒有進行resolve
谷饿、reject
所以then
中的回調(diào)也無法執(zhí)行。
? 此時引入Pending(進行中)妈倔、Fulfilled(已成功)博投、Rejected(已失敗)
狀態(tài)盯蝴,resolve()
可以將Pending
轉(zhuǎn)變?yōu)?code>Fulfilled,同理reject()
將Pending
轉(zhuǎn)變?yōu)?code>Rejected狀態(tài)
? new MyPromise(handle1).then(handle1)
執(zhí)行到then()
時如果有異步操作毅哗,那么狀態(tài)仍為Peding
,此時將then
的回調(diào)都儲存起來捧挺,等待resolve()虑绵、reject()
執(zhí)行時再執(zhí)行。
此步驟完成代碼如下:
const PENDING = 'PENDING'//進行中
const FULFILLED = 'FULFILLED'//已成功
const REJECTED = 'REJECTED' //已失敗
class MyPromise{
constructor(handle){
this._value = null
this._status = PENDING
// 添加成功回調(diào)函數(shù)隊列
this._fulfilledQueues = []
// 添加失敗回調(diào)函數(shù)隊列
this._rejectedQueues = []
handle(this._resolve.bind(this),this._reject.bind(this))
}
_resolve(val){
if (this._status !== PENDING) return//狀態(tài)不可逆闽烙,只能從PENDING——》FULFILLED翅睛,不能從別的狀態(tài)到FULFILLED
this._value=val
this._status=FULFILLED
let cb
while (cb=this._fulfilledQueues.shift()){//依次執(zhí)行成功隊列中的函數(shù),并清空隊列
cb(val)
}
}
_reject(val){
if (this._status !== PENDING) return//狀態(tài)不可逆黑竞,只能從PENDING——》REJECTED捕发,不能從別的狀態(tài)到REJECTED
this._value= val
this._status=REJECTED
let cb
while (cb=this._rejectedQueues.shift()){//依次執(zhí)行失敗隊列中的函數(shù),并清空隊列
cb(val)
}
}
}
//使用例子
MyPromise.prototype.then=function (onFulfilled,onRejected) {
switch (this._status) {
case PENDING: this._fulfilledQueues.push(onFulfilled)//待選擇很魂,待執(zhí)行的回頭添加到隊列
this._rejectedQueues.push(onRejected)
break
case FULFILLED: onFulfilled(this._value);break;
case REJECTED: onRejected(this._value);break;
}
}
new MyPromise(function (resolve,reject) {
setTimeout(function () {
resolve('call resolve')
},1000)
}).then(function (val) {
console.log(val)
})//1秒之后輸出 call resolve
new MyPromise(function (resolve,reject) {
setTimeout(function () {
reject('call reject')
},2000)
}).then(function () {},function (val) {
console.log(val)
})//2秒之后輸出 call reject
3.鏈?zhǔn)秸{(diào)用
3.1鏈?zhǔn)?/h4>
? 定義then
方法時:
? 讓then
返回一個MyPromise
對象可實現(xiàn)鏈?zhǔn)秸{(diào)用扎酷。
onFullfilled(val)
或onRejectedNext(val)
的調(diào)用決定了new MyPromise().then().then(res,rej)
中的第二個then的回調(diào)什么時候調(diào)用,收到的傳參是多少遏匆。
MyPromise.prototype.then(function(onFullfilled,onRejected){
return new MyPromise(function(onFullfilledNext,onRejectedNext){
onFullfilledNext(val)//onRejectedNext(val)
})
})
3.2鏈?zhǔn)脚c異步
常見情況下法挨,onFullfilledNext
的調(diào)用時間取決于onFullfilled
的調(diào)用時間谁榜,onFullfilledNext(val)
傳遞的參數(shù)val
是onFullfilled
的返回值
但是在異步情況下,onFullfilled
是傳入._fulfilledQueues
隊列中等待執(zhí)行的,所以將onFullfilled
打包在fulfilled
中延遲調(diào)用凡纳,將fulfilled
代替onFullfilled
放入隊列窃植。fulfilled
中onFullfilledNext
根據(jù)onFullfilled
的返回值傳參。
此步驟代碼:
function isFunction(fn) {
return typeof fn === 'function'
}
const PENDING = 'PENDING'//進行中
const FULFILLED = 'FULFILLED'//已成功
const REJECTED = 'REJECTED' //已失敗
class MyPromise{
constructor(handle){
this._value = null
this._status = PENDING
// 添加成功回調(diào)函數(shù)隊列
this._fulfilledQueues = []
// 添加失敗回調(diào)函數(shù)隊列
this._rejectedQueues = []
try{
handle(this._resolve.bind(this),this._reject.bind(this))
}catch (err) {
this._reject(err)
}
}
_resolve(val){
const run=() => {
if (this._status !== PENDING) return//狀態(tài)不可逆惫企,只能從PENDING——》FULFILLED撕瞧,不能從別的狀態(tài)到FULFILLED
// 依次執(zhí)行成功隊列中的函數(shù)陵叽,并清空隊列
const runFulfilled = (value) => {
let cb;
while (cb = this._fulfilledQueues.shift()) {
cb(value)
}
}
// 依次執(zhí)行失敗隊列中的函數(shù)狞尔,并清空隊列
const runRejected = (error) => {
let cb;
while (cb = this._rejectedQueues.shift()) {
cb(error)
}
}
if(val instanceof MyPromise){
val.then((value)=>{
this._value=value
this._status=FULFILLED
runFulfilled(value)
},(err)=>{
this._value=err
this._status=REJECTED
runRejected(err)
})
}else {
this._value=val
this._status=FULFILLED
runFulfilled(val)
}
}
setTimeout(run,0)
}
_reject(err){
if (this._status !== PENDING) return//狀態(tài)不可逆,只能從PENDING——》REJECTED巩掺,不能從別的狀態(tài)到REJECTED
this._value= err
this._status=REJECTED
let cb
while (cb=this._rejectedQueues.shift()){//依次執(zhí)行失敗隊列中的函數(shù)偏序,并清空隊列
cb(err)
}
}
}
MyPromise.prototype.then=function (onFulfilled,onRejected) {
return new MyPromise( (onFulfilledNext,onRejectedNext) => {
let fulfilled=(value) => {
try {
let result = onFulfilled(value)
onFulfilledNext(result)
}catch (err) {
onRejectedNext(err)
}
}
let rejected=(value) => {
try{
let result =onRejected(value)
onRejectedNext(result)
}catch (err) {
onRejectedNext(err)
}
}
switch(this._status){
case PENDING : this._fulfilledQueues.push(fulfilled)
this._rejectedQueues.push(rejected)
break
case FULFILLED :fulfilled(this._value)
break
case REJECTED : rejected(this._value)
break
}
})
}
//使用例子
new MyPromise(function (resolve,reject) {
setTimeout(function () {
resolve(new MyPromise(function (resolve) {
resolve('promise in resolve')
}))
},1000)
}).then(function (val) {
console.log('first then,get message :'+val)//1秒之后輸出 first then,get message :promise in resolve
return 'val form 1st then to 2nd then'
}).then(function (val) {
console.log('second then,get message:'+val)//1秒之后輸出 second then,get message:val form 1st then to 2nd then
})
3.3值穿透與then
的回調(diào)返回MyPromise
對象
1.onFullfilled——》對應(yīng)調(diào)用onFullfilledNext
onFullfilled
也就是第一個then
的res
回調(diào)
? onFullfilled
不為function時:值穿透,直接onFullfilledNext(onFullFiled)
? onFullfilled
為function時:1.如果返回值不為Promise胖替,onFullfilledNext(返回值)
? 2.如果返回值為Promise時研儒,返回值.then(onFullfilled)
。將onFullfilledNext
傳給then當(dāng)回調(diào)独令,由Promise
決定何時將執(zhí)行權(quán)傳遞給then
?
2.onRejected——》對應(yīng)調(diào)用onRejectedNext
onRejected
也就是then的rej
回調(diào)
? onRejected
不為function
時:值穿透端朵,直接調(diào)用onRejectedNext(onRejected)
? onRejected
為function
時:1.返回值不為Promise
,調(diào)用onRejectedNext(返回值)
? 2.返回值為Promise
,調(diào)用返回值.then(onRejectedNext)
4.new Promise中resolve傳遞的值為Promise的實例
resolve(new Promise)
第一個Promise
中狀態(tài)取決于resolve中的Promise
也就是說resolve中的Promise
的then回調(diào)執(zhí)行時就能確定第一個Promise
的狀態(tài)
例如下面這種使用形式:
new Promise(function (resolve,reject) {
return resolve(new Promise(function () {
}))
}).then(function () {
},function () {
})
所以在實現(xiàn)MyPromise
中的_resolve
時燃箭,如果_resolve(val)
中的值為Promise的實例,instanceof val=== MyPromise
那么在val.then()
的兩個回調(diào)中改變MyPromise
的狀態(tài)
代碼
function isFunction(fn) {
return typeof fn === 'function'
}
const PENDING = 'PENDING'//進行中
const FULFILLED = 'FULFILLED'//已成功
const REJECTED = 'REJECTED' //已失敗
class MyPromise{
constructor(handle){
this._value = null
this._status = PENDING
// 添加成功回調(diào)函數(shù)隊列
this._fulfilledQueues = []
// 添加失敗回調(diào)函數(shù)隊列
this._rejectedQueues = []
try{
handle(this._resolve.bind(this),this._reject.bind(this))
}catch (err) {
this._reject(err)
}
}
_resolve(val){
const run=() => {
if (this._status !== PENDING) return//狀態(tài)不可逆冲呢,只能從PENDING——》FULFILLED,不能從別的狀態(tài)到FULFILLED
// 依次執(zhí)行成功隊列中的函數(shù)招狸,并清空隊列
const runFulfilled = (value) => {
let cb;
while (cb = this._fulfilledQueues.shift()) {
cb(value)
}
}
// 依次執(zhí)行失敗隊列中的函數(shù)敬拓,并清空隊列
const runRejected = (error) => {
let cb;
while (cb = this._rejectedQueues.shift()) {
cb(error)
}
}
if(val instanceof MyPromise){
val.then((value)=>{
this._value=value
this._status=FULFILLED
runFulfilled(value)
},(err)=>{
this._value=err
this._status=REJECTED
runRejected(err)
})
}else {
this._value=val
this._status=FULFILLED
runFulfilled(val)
}
}
setTimeout(run,0)
}
_reject(err){
if (this._status !== PENDING) return//狀態(tài)不可逆,只能從PENDING——》REJECTED裙戏,不能從別的狀態(tài)到REJECTED
this._value= err
this._status=REJECTED
let cb
while (cb=this._rejectedQueues.shift()){//依次執(zhí)行失敗隊列中的函數(shù)乘凸,并清空隊列
cb(err)
}
}
}
MyPromise.prototype.then=function (onFulfilled,onRejected) {
return new MyPromise( (onFulfilledNext,onRejectedNext) => {
let fulfilled=(value) => {
if(!isFunction(onFulfilled)) {
onFulfilledNext(value) //值穿透
return
}
try {
let result = onFulfilled(value)
if(result instanceof MyPromise){
result.then(onFulfilledNext,onRejectedNext)
}else {
onFulfilledNext(result)
}
}catch (err) {
onRejectedNext(err)
}
}
let rejected=(value) => {
if(!isFunction(onFulfilled)) {
onRejectedNext(value)
return
}
try{
let result =onRejected(value)
if(result instanceof MyPromise){
result.then(onFulfilledNext,onRejectedNext)
} else {
onRejectedNext(result)
}
}catch (err) {
onRejectedNext(err)
}
}
switch(this._status){
case PENDING : this._fulfilledQueues.push(fulfilled)
this._rejectedQueues.push(rejected)
break
case FULFILLED :fulfilled(this._value)
break
case REJECTED : rejected(this._value)
break
}
})
}
//使用例子
new MyPromise(function (resolve,reject) {
setTimeout(function () {
resolve(new MyPromise(function (resolve) {
resolve('promise in resolve')
}))
},1000)
}).then(function (val) {
console.log('first then,get message :'+val)//1秒之后輸出 first then,get message :promise in resolve
return new MyPromise(function (resolve) {
setTimeout(()=>{
return resolve('promise in then')
},1000)
})
}).then(function (val) {
console.log('second then ,get message:'+val)//2秒之后輸出 second then ,get message:promise in then
})