最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript面試必備技巧之手寫(xiě)一個(gè)Promise

 更新時(shí)間:2023年02月08日 15:06:59   作者:mick  
很多同學(xué)在面試的時(shí)候都會(huì)被要求手寫(xiě)一個(gè)Promise,那么今天我總結(jié)了一些手寫(xiě)Promise的方法,可以跟著我的思路一起來(lái)實(shí)現(xiàn)一個(gè)Promise,讓我們的面試更有把握

很多同學(xué)在面試的時(shí)候都會(huì)被要求手寫(xiě)一個(gè)Promise,那么今天我總結(jié)了一些手寫(xiě)Promise的方法,可以跟著我的思路一起來(lái)實(shí)現(xiàn)一個(gè)Promise,讓我們的面試更有把握。同時(shí)我們也會(huì)實(shí)現(xiàn)一下Promsie常見(jiàn)的方法比如:all、race、allSettled、any。

基本實(shí)現(xiàn)

首先我們可以用類(lèi)來(lái)實(shí)現(xiàn)Promise,而且Promise有三種狀態(tài):pending、fulfilled、rejected。初始狀態(tài)為pending。還需要對(duì)Promise的終值進(jìn)行初始化。Promise還有兩個(gè)方法resolve和reject。

Promise有四個(gè)特點(diǎn):

  • 執(zhí)行了resolve,Promise狀態(tài)就會(huì)變成fulfilled
  • 執(zhí)行了reject,Promise狀態(tài)就會(huì)變成rejected
  • Promise狀態(tài)不可逆,第一次成功就永久為fulfilled,第一次失敗就永久為rejected
  • Promise中有throw的話,就相當(dāng)于執(zhí)行了rejected

下面我就來(lái)簡(jiǎn)單的實(shí)現(xiàn)一下吧

實(shí)現(xiàn)resolve和reject

class MyPromise {
  constructor(executor) {
    // 初始化值
    this.initValue()
    // 初始化this指向
    this.initBind()

    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }

  initValue() {
    // 初始化值
    this.promiseResult = null
    this.promiseState = "pending" // 初始狀態(tài)
  }

  initBind() {
    this.resolve = this.resolve.bind(this)
    this.reject = this.reject.bind(this)
  }

  resolve(val) {
    this.promiseState = "fulfilled"
    this.promiseResult = val
  }

  reject(reason) {
    this.promiseState = "rejected"
    this.promiseResult = reason
  }
}

測(cè)試一下吧

const test1 = new MyPromise((resolve, reject) => {
  resolve("success")
})

console.log(test1) 
// MyPromise{ promiseResult: 'success', promiseState: 'fulfilled' }

const test2 = new MyPromise((resolve, reject) => {
  reject("fail")
})

console.log(test2)
// MyPromise{ promiseResult: 'fail', promiseState: 'rejected' }

const test3 = new MyPromise((resolve, reject) => {
  throw "fail"
})
console.log(test3)
// MyPromise{ promiseResult: 'fail', promiseState: 'rejected' }

這里重點(diǎn)說(shuō)一下initBind中為什么要給resolve和reject綁定this。我們可以看到在resolve和reject中使用了this.promiseStatethis.promiseResult。我們需要把它的this綁定到實(shí)例才對(duì)。

狀態(tài)不可變

如果我們執(zhí)行下面的代碼

const test = new MyPromise((resolve, reject) => {
  resolve("success")
  reject("fail")
})
console.log(test)
// MyPromise{ promiseResult: 'fail', promiseState: 'rejected' }

這就不符合我們的預(yù)期了,因?yàn)槲覀冃枰氖菭顟B(tài)不可變。所以我們將代碼改造一下,這里只需要修改resolve和reject就可以了

resolve(val) {
    if (this.promiseState !== "pending") return
    this.promiseState = "fulfilled"
    this.promiseResult = val
}

reject(reason) {
    if (this.promiseState !== "pending") return
    this.promiseState = "rejected"
    this.promiseResult = reason
}

當(dāng)執(zhí)行resolve或reject的時(shí)候,發(fā)現(xiàn)狀態(tài)不是pending就說(shuō)明狀態(tài)已經(jīng)改變了,直接return即可。

then

我們首先看下原始的Promise的then實(shí)現(xiàn)的效果

// 直接輸出success
const p1 = new Promise((resolve, reject) => {
  resolve("success")
}).then(
  (res) => console.log(res),
  (err) => console.log(err)
)

// 1s后輸出fail
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("fail")
  }, 1000)
}).then(
  (res) => console.log(res),
  (err) => console.log(err)
)

// 鏈?zhǔn)秸{(diào)用 直接輸出2000
const p3 = new Promise((resolve, reject) => {
  resolve(1000)
})
  .then(
    (res) => 2 * res,
    (err) => console.log(err)
  )
  .then(
    (res) => console.log(res),
    (err) => console.log(err)
  )

由此可以得出結(jié)論:

  • then 接受兩個(gè)回調(diào),一個(gè)是成功回調(diào), 一個(gè)是失敗的回調(diào)
  • 當(dāng)Promise為fulfilled執(zhí)行成功的回調(diào),為rejected 執(zhí)行失敗的回調(diào)
  • 如果resolve或者reject在定時(shí)器里面執(zhí)行,則定時(shí)器結(jié)束后再執(zhí)行then
  • then 支持鏈?zhǔn)秸{(diào)用,下一次then執(zhí)行受上一次then返回值的影響

then實(shí)現(xiàn)

由結(jié)論1和2可以實(shí)現(xiàn)

then(onFulfilled, onRejected) {
    // 首先要校驗(yàn)兩個(gè)回調(diào)是否是函數(shù)
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (val) => val
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason
          }

    if (this.promiseState === "fulfilled") {
      onFulfilled(this.promiseResult)
    } else if (this.promiseState === "rejected") {
      onRejected(this.promiseResult)
    }
}

但是我們?nèi)绾伪WC回調(diào)是在定時(shí)器結(jié)束后執(zhí)行呢?首先在定時(shí)器結(jié)束之前Promise的狀態(tài)一直是pending的,回調(diào)結(jié)束之后我們才能知道是fulfilled或者是rejected,所以在執(zhí)行then的時(shí)候,如果promiseState是pending我們就把回調(diào)收集起來(lái),當(dāng)回調(diào)結(jié)束之后再觸發(fā)。那使用什么來(lái)保存這些回調(diào)的呢?這里建議使用數(shù)組,因?yàn)橐粋€(gè)Promise實(shí)例可能會(huì)多次執(zhí)行then,用數(shù)組一個(gè)個(gè)保存就可以了

initValue() {
    // 初始化值
    this.promiseResult = null
    this.promiseState = "pending" // 初始狀態(tài)
    this.onFulfilledCallbacks = []
    this.onRejectedCallbacks = []
}
resolve(val) {
    if (this.promiseState !== "pending") return
    this.promiseState = "fulfilled"
    this.promiseResult = val
    while (this.onFulfilledCallbacks.length) {
      this.onFulfilledCallbacks.shift()(this.promiseResult)
    }
}

reject(reason) {
    if (this.promiseState !== "pending") return
    this.promiseState = "rejected"
    this.promiseResult = reason
    while (this.onRejectedCallbacks.length) {
      this.onRejectedCallbacks.shift()(this.promiseResult)
    }
}
then(onFulfilled, onRejected) {
    // 首先要校驗(yàn)兩個(gè)回調(diào)是否是函數(shù)
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (val) => val
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason
          }

    if (this.promiseState === "fulfilled") {
      onFulfilled(this.promiseResult)
    } else if (this.promiseState === "rejected") {
      onRejected(this.promiseResult)
    } else if (this.promiseState === "pending") {
      this.onFulfilledCallbacks.push(onFulfilled.bind(this))
      this.onRejectedCallbacks.push(onRejected.bind(this))
    }
}

鏈?zhǔn)秸{(diào)用

我們?cè)賮?lái)重新看下鏈?zhǔn)秸{(diào)用的例子

// 鏈?zhǔn)秸{(diào)用 直接輸出2000
const p3 = new Promise((resolve, reject) => {
  resolve(1000)
})
  .then(
    (res) => 2 * res,
    (err) => console.log(err)
  )
  .then(
    (res) => console.log(res),
    (err) => console.log(err)
  )

// 鏈?zhǔn)秸{(diào)用 輸出3000
const p4 = new Promise((resolve, reject) => {
  resolve(1000)
})
  .then(
    (res) => new Promise((resolve, reject) => resolve(3 * res)),
    (err) => console.log(err)
  )
  .then(
    (res) => console.log(res),
    (err) => console.log(err)
  )

由此可得:

  • then方法本身會(huì)返回一個(gè)新的Promise對(duì)象
  • 如果返回值是promise對(duì)象,返回值為成功,新promise就是成功
  • 如果返回值是promise對(duì)象,返回值為失敗,新promise就是失敗
  • 如果返回值是非promise對(duì)象,新promise對(duì)象就是成功,值為此返回值

這里我們對(duì)then改造了一下

then(onFulfilled, onRejected) {
    // 首先要校驗(yàn)兩個(gè)回調(diào)是否是函數(shù)
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (val) => val
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason
          }

    var thenPromise = new MyPromise((resolve, reject) => {
      const resolvePromise = (cb) => {
        try {
          const x = cb(this.promiseResult)

          if (x === thenPromise && x) {
            throw new Error("不能返回自身")
          }
          if (x instanceof MyPromise) {
            // 如果是promise 返回值為成功 新promise 就是成功
            // 如果是promise 返回值失敗 新promise  就是失敗
            x.then(resolve, reject)
          } else {
            // 如果不是promise 直接返回成功
            resolve(x)
          }
        } catch (error) {
          reject(error)
          throw new Error(error)
        }
      }

      if (this.promiseState === "fulfilled") {
        resolvePromise(onFulfilled)
      } else if (this.promiseState === "rejected") {
        resolvePromise(onRejected)
      } else if (this.promiseState === "pending") {
        this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled))
        this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected))
      }
    })

    return thenPromise
  }

then會(huì)返回一個(gè)新的Promise,在這個(gè)新的promise中定義了方法resolvePromise ,接收一個(gè)cb回調(diào)函數(shù),這個(gè)cb就是傳入的onFulfilled或者onRejected。如果這兩個(gè)回調(diào)返回的不是promise,那結(jié)果直接resolve出去。如果是promise,那么就需要根據(jù)它的狀態(tài)來(lái)決定下一步操作。那它到底是成功還是失敗的呢,只有它的then知道。然后把resolve和reject當(dāng)做回調(diào)傳給then,如果x返回的是成功的Promise,則會(huì)執(zhí)行resolve, 如果x返回的是失敗的promise,則會(huì)執(zhí)行reject。這樣鏈?zhǔn)秸{(diào)用的then才會(huì)知道執(zhí)行哪一個(gè)回調(diào)。

執(zhí)行順序

const p = new Promise((resolve, reject) => {
  resolve(1)
}).then(
  (res) => console.log(res),
  (err) => console.log(err)
)

console.log(2)

為了實(shí)現(xiàn)類(lèi)似的功能,使用setTimeout代替

看下完整代碼

class MyPromise {
  constructor(executor) {
    // 初始化值
    this.initValue()
    // 初始化this指向
    this.initBind()

    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }

  initValue() {
    // 初始化值
    this.promiseResult = null
    this.promiseState = "pending" // 初始狀態(tài)
    this.onFulfilledCallbacks = []
    this.onRejectedCallbacks = []
  }

  initBind() {
    this.resolve = this.resolve.bind(this)
    this.reject = this.reject.bind(this)
  }

  resolve(val) {
    if (this.promiseState !== "pending") return
    this.promiseState = "fulfilled"
    this.promiseResult = val
    while (this.onFulfilledCallbacks.length) {
      this.onFulfilledCallbacks.shift()(this.promiseResult)
    }
  }

  reject(reason) {
    if (this.promiseState !== "pending") return
    this.promiseState = "rejected"
    this.promiseResult = reason
    while (this.onRejectedCallbacks.length) {
      this.onRejectedCallbacks.shift()(this.promiseResult)
    }
  }

  then(onFulfilled, onRejected) {
    // 首先要校驗(yàn)兩個(gè)回調(diào)是否是函數(shù)
    onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (val) => val
    onRejected =
      typeof onRejected === "function"
        ? onRejected
        : (reason) => {
            throw reason
          }

    var thenPromise = new MyPromise((resolve, reject) => {
      const resolvePromise = (cb) => {
        setTimeout(() => {
          try {
            const x = cb(this.promiseResult)

            if (x === thenPromise && x) {
              throw new Error("不能返回自身")
            }

            if (x instanceof MyPromise) {
              // 如果是promise 返回值為成功 新promise 就是成功
              // 如果是promise 返回值失敗 新promise  就是失敗
              x.then(resolve, reject)
            } else {
              // 如果不是promise 直接返回成功
              resolve(x)
            }
          } catch (error) {
            reject(error)
            throw new Error(error)
          }
        })
      }

      if (this.promiseState === "fulfilled") {
        resolvePromise(onFulfilled)
      } else if (this.promiseState === "rejected") {
        resolvePromise(onRejected)
      } else if (this.promiseState === "pending") {
        this.onFulfilledCallbacks.push(resolvePromise.bind(this, onFulfilled))
        this.onRejectedCallbacks.push(resolvePromise.bind(this, onRejected))
      }
    })

    return thenPromise
  }
}

其他方法

all

  • 接收一個(gè)Promise數(shù)組,數(shù)組中如有非Promise項(xiàng),則此項(xiàng)當(dāng)做成功
  • 如果所有Promise都成功,則返回成功結(jié)果數(shù)組
  • 如果有一個(gè)Promise失敗,則返回這個(gè)失敗的結(jié)果
static all(promiseList) {
    const result = []
    const count = 0

    return new MyPromise((resolve, reject) => {
      const addData = function (index, value) {
        result[index] = value
        count++

        if (count === promiseList.length) resolve(result)
      }

      promiseList.forEach((promise, index) => {
        if (promise instanceof MyPromise) {
          promise.then(
            (res) => {
              addData(index, res)
            },
            (err) => {
              reject(err)
            }
          )
        } else {
          addData(index, promise)
        }
      })
    })
}

race

  • 接收一個(gè)Promise數(shù)組,數(shù)組中有非Promise項(xiàng),則此項(xiàng)當(dāng)做成功
  • 哪個(gè)Promise最快得到結(jié)果,就返回那個(gè)結(jié)果,無(wú)論成功失敗
race(promiseList) {
    return new MyPromise((resolve, reject) => {
      promiseList.forEach((promise) => {
        if (promise instanceof MyPromise) {
          promise.then(
            (res) => resolve(res),
            (err) => reject(err)
          )
        } else {
          resolve(promise)
        }
      })
    })
}

allSettled

  • 接收一個(gè)Promise數(shù)組,數(shù)組中有非Promise項(xiàng),則此項(xiàng)當(dāng)做成功
  • 把每個(gè)Promise的結(jié)果,集合成數(shù)組后返回
allSettled(promiseList) {
    const result = []
    let count = 0
    return new MyPromise((resolve, reject) => {
      const addData = function (status, value, i) {
        result[i] = {
          status,
          value
        }

        count++
        if (count === promiseList.length) {
          resolve(result)
        }
      }

      promiseList.forEach((promise, index) => {
        if (promise instanceof MyPromise) {
          promise.then(
            (res) => {
              addData("fulfilled", res, index)
            },
            (err) => {
              addData("reject", err, index)
            }
          )
        } else {
          resolve(promise)
        }
      })
    })
}

any

與all相反

  • 接收一個(gè)Promise數(shù)組,數(shù)組中如有非Promise項(xiàng),則此項(xiàng)當(dāng)做成功
  • 如果有一個(gè)Promise成功,則返回這個(gè)成功結(jié)果
  • 如果所有Promise都失敗,則報(bào)錯(cuò)
static any(promiseList) {
    return new MyPromise((resolve, reject) => {
      let count = 0
      promiseList.forEach((promise) => {
        if (promise instanceof MyPromise) {
          promise.then(
            (res) => {
              resolve(res)
            },
            (err) => {
              count++
              if (count === promiseList.length) {
                reject("error")
              }
            }
          )
        } else {
          resolve(promise)
        }
      })
    })
  }

到此這篇關(guān)于JavaScript面試必備技巧之手寫(xiě)一個(gè)Promise的文章就介紹到這了,更多相關(guān)JavaScript手寫(xiě)Promise內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JS實(shí)現(xiàn)秒殺倒計(jì)時(shí)特效

    JS實(shí)現(xiàn)秒殺倒計(jì)時(shí)特效

    這篇文章主要為大家詳細(xì)介紹了JS實(shí)現(xiàn)秒殺倒計(jì)時(shí)特效,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-01-01
  • Javascript實(shí)現(xiàn)信息滾動(dòng)效果

    Javascript實(shí)現(xiàn)信息滾動(dòng)效果

    這篇文章主要為大家詳細(xì)介紹了Javascript實(shí)現(xiàn)信息滾動(dòng)效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-05-05
  • 2022發(fā)布ECMAScript新特性盤(pán)點(diǎn)

    2022發(fā)布ECMAScript新特性盤(pán)點(diǎn)

    這篇文章主要為大家介紹了2022發(fā)布ECMAScript新特性盤(pán)點(diǎn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • AngularJs+Bootstrap實(shí)現(xiàn)漂亮的計(jì)算器

    AngularJs+Bootstrap實(shí)現(xiàn)漂亮的計(jì)算器

    這篇文章主要為大家詳細(xì)介紹了angularJs+Bootstrap實(shí)現(xiàn)漂亮的計(jì)算器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08
  • PHP7新特性簡(jiǎn)述

    PHP7新特性簡(jiǎn)述

    本文通過(guò)實(shí)例給大家介紹了PHP7新特性的相關(guān)知識(shí),需要的朋友參考下吧
    2017-06-06
  • JS逆向之愛(ài)奇藝滑塊加密的實(shí)現(xiàn)

    JS逆向之愛(ài)奇藝滑塊加密的實(shí)現(xiàn)

    本文主要介紹了JS逆向之愛(ài)奇藝滑塊加密的實(shí)現(xiàn),文中根據(jù)實(shí)例編碼詳細(xì)介紹的十分詳盡,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • JS中捕獲console.log()輸出的方法

    JS中捕獲console.log()輸出的方法

    這篇文章主要介紹了JS中捕獲console.log()輸出的方法,實(shí)例分析了實(shí)現(xiàn)獲取console.log輸出的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-04-04
  • uniapp跨頁(yè)面?zhèn)鲄⒌膸追N方式小結(jié)

    uniapp跨頁(yè)面?zhèn)鲄⒌膸追N方式小結(jié)

    當(dāng)我們?cè)陂_(kāi)發(fā)Uni-app應(yīng)用時(shí),經(jīng)常會(huì)遇到需要在不同頁(yè)面之間傳遞參數(shù)的情況,為了實(shí)現(xiàn)跨頁(yè)面?zhèn)鲄?Uni-app提供了幾種方式,所以本文小編將給大家介紹一下uniapp跨頁(yè)面?zhèn)鲄⒌膸追N方式,文中有詳細(xì)的代碼示例供大家參考,需要的朋友可以參考下
    2024-01-01
  • js驗(yàn)證IP及子網(wǎng)掩碼的合法性有效性示例

    js驗(yàn)證IP及子網(wǎng)掩碼的合法性有效性示例

    這篇文章主要介紹了js驗(yàn)證IP及子網(wǎng)掩碼的有效性,需要的朋友可以參考下
    2014-04-04
  • javascript 操作文件 實(shí)現(xiàn)方法小結(jié)

    javascript 操作文件 實(shí)現(xiàn)方法小結(jié)

    可以通過(guò)瀏覽器在訪問(wèn)者的硬盤(pán)上創(chuàng)建文件 JavaScript操作文件系統(tǒng)創(chuàng)建快捷方式
    2009-07-07

最新評(píng)論

晋州市| 抚远县| 沾化县| 邻水| 钟祥市| 广州市| 团风县| 文登市| 北京市| 勐海县| 蛟河市| 商洛市| 望江县| 沙湾县| 郴州市| 河东区| 新兴县| 马尔康县| 安仁县| 洱源县| 安达市| 驻马店市| 桓仁| 界首市| 通江县| 乐安县| 河曲县| 延寿县| 辽阳市| 东源县| 黔江区| 沙湾县| 和田县| 邮箱| 微博| 宽甸| 吴堡县| 静宁县| 文登市| 肃宁县| 屏东县|