国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

JavaScript之手寫Promise

stefan / 3202人閱讀

摘要:如果狀態是等待態的話,就往回調函數中函數,比如如下代碼就會進入等待態的邏輯以上就是簡單版實現實現一個符合規范的接下來大部分代碼都是根據規范去實現的。

為更好的理解, 推薦閱讀Promise/A+ 規范
實現一個簡易版 Promise

在完成符合 Promise/A+ 規范的代碼之前,我們可以先來實現一個簡易版 Promise,因為在面試中,如果你能實現出一個簡易版的 Promise 基本可以過關了。

那么我們先來搭建構建函數的大體框架

const PENDING = "pending"
const RESOLVED = "resolved"
const REJECTED = "rejected"

function MyPromise(fn) {
  const that = this
  that.state = PENDING
  that.value = null
  that.resolvedCallbacks = []
  that.rejectedCallbacks = []
  // 待完善 resolve 和 reject 函數
  // 待完善執行 fn 函數
}

首先我們創建了三個常量用于表示狀態,對于經常使用的一些值都應該通過常量來管理,便于開發及后期維護

在函數體內部首先創建了常量 that,因為代碼可能會異步執行,用于獲取正確的 this 對象

一開始 Promise 的狀態應該是 pending

value 變量用于保存 resolve 或者 reject 中傳入的值

resolvedCallbacksrejectedCallbacks 用于保存 then 中的回調,因為當執行完 Promise 時狀態可能還是等待中,這時候應該把 then 中的回調保存起來用于狀態改變時使用

接下來我們來完善 resolve 和 reject 函數,添加在 MyPromise 函數體內部

function resolve(value) {
  if (that.state === PENDING) {
    that.state = RESOLVED
    that.value = value
    that.resolvedCallbacks.map(cb => cb(that.value))
  }
}

function reject(value) {
  if (that.state === PENDING) {
    that.state = REJECTED
    that.value = value
    that.rejectedCallbacks.map(cb => cb(that.value))
  }
}

這兩個函數代碼類似,就一起解析了

首先兩個函數都得判斷當前狀態是否為等待中,因為規范規定只有等待態才可以改變狀態

將當前狀態更改為對應狀態,并且將傳入的值賦值給 value

遍歷回調數組并執行

完成以上兩個函數以后,我們就該實現如何執行 Promise 中傳入的函數了

try {
  fn(resolve, reject)
} catch (e) {
  reject(e)
}

實現很簡單,執行傳入的參數并且將之前兩個函數當做參數傳進去

要注意的是,可能執行函數過程中會遇到錯誤,需要捕獲錯誤并且執行 reject 函數

最后我們來實現較為復雜的 then 函數

MyPromise.prototype.then = function(onFulfilled, onRejected) {
  const that = this
  onFulfilled = typeof onFulfilled === "function" ? onFulfilled : v => v
  onRejected =
    typeof onRejected === "function"
      ? onRejected
      : r => {
          throw r
        }
  if (that.state === PENDING) {
    that.resolvedCallbacks.push(onFulfilled)
    that.rejectedCallbacks.push(onRejected)
  }
  if (that.state === RESOLVED) {
    onFulfilled(that.value)
  }
  if (that.state === REJECTED) {
    onRejected(that.value)
  }
}

首先判斷兩個參數是否為函數類型,因為這兩個參數是可選參數

當參數不是函數類型時,需要創建一個函數賦值給對應的參數,同時也實現了透傳,比如如下代碼

// 該代碼目前在簡單版中會報錯
// 只是作為一個透傳的例子
Promise.resolve(4).then().then((value) => console.log(value))

接下來就是一系列判斷狀態的邏輯,當狀態不是等待態時,就去執行相對應的函數。如果狀態是等待態的話,就往回調函數中 push 函數,比如如下代碼就會進入等待態的邏輯

new MyPromise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 0)
}).then(value => {
  console.log(value)
})

以上就是簡單版 Promise 實現

實現一個符合 Promise/A+ 規范的 Promise
接下來大部分代碼都是根據規范去實現的。

我們先來改造一下 resolvereject 函數

function resolve(value) {
  if (value instanceof MyPromise) {
    return value.then(resolve, reject)
  }
  setTimeout(() => {
    if (that.state === PENDING) {
      that.state = RESOLVED
      that.value = value
      that.resolvedCallbacks.map(cb => cb(that.value))
    }
  }, 0)
}
function reject(value) {
  setTimeout(() => {
    if (that.state === PENDING) {
      that.state = REJECTED
      that.value = value
      that.rejectedCallbacks.map(cb => cb(that.value))
    }
  }, 0)
}

對于 resolve 函數來說,首先需要判斷傳入的值是否為 Promise 類型

為了保證函數執行順序,需要將兩個函數體代碼使用 setTimeout 包裹起來

接下來繼續改造 then 函數中的代碼,首先我們需要新增一個變量 promise2,因為每個 then 函數都需要返回一個新的 Promise 對象,該變量用于保存新的返回對象,然后我們先來改造判斷等待態的邏輯

if (that.state === PENDING) {
  return (promise2 = new MyPromise((resolve, reject) => {
    that.resolvedCallbacks.push(() => {
      try {
        const x = onFulfilled(that.value)
        resolutionProcedure(promise2, x, resolve, reject)
      } catch (r) {
        reject(r)
      }
    })

    that.rejectedCallbacks.push(() => {
      try {
        const x = onRejected(that.value)
        resolutionProcedure(promise2, x, resolve, reject)
      } catch (r) {
        reject(r)
      }
    })
  }))
}

首先我們返回了一個新的 Promise 對象,并在 Promise 中傳入了一個函數

函數的基本邏輯還是和之前一樣,往回調數組中 push 函數

同樣,在執行函數的過程中可能會遇到錯誤,所以使用了 try...catch 包裹

規范規定,執行 onFulfilled 或者 onRejected 函數時會返回一個 x,并且執行 Promise 解決過程,這是為了不同的 Promise 都可以兼容使用,比如 JQueryPromise 能兼容 ES6Promise

接下來我們改造判斷執行態的邏輯

if (that.state === RESOLVED) {
  return (promise2 = new MyPromise((resolve, reject) => {
    setTimeout(() => {
      try {
        const x = onFulfilled(that.value)
        resolutionProcedure(promise2, x, resolve, reject)
      } catch (reason) {
        reject(reason)
      }
    })
  }))
}

其實大家可以發現這段代碼和判斷等待態的邏輯基本一致,無非是傳入的函數的函數體需要異步執行,這也是規范規定的

對于判斷拒絕態的邏輯這里就不一一贅述了,留給大家自己完成這個作業

最后,當然也是最難的一部分,也就是實現兼容多種 PromiseresolutionProcedure 函數

function resolutionProcedure(promise2, x, resolve, reject) {
  if (promise2 === x) {
    return reject(new TypeError("Error"))
  }
}

首先規范規定了 x 不能與 promise2 相等,這樣會發生循環引用的問題,比如如下代碼

let p = new MyPromise((resolve, reject) => {
  resolve(1)
})
let p1 = p.then(value => {
  return p1
})

然后需要判斷 x 的類型

if (x instanceof MyPromise) {
    x.then(function(value) {
        resolutionProcedure(promise2, value, resolve, reject)
    }, reject)
}

這里的代碼是完全按照規范實現的。如果 xPromise 的話,需要判斷以下幾個情況:

如果 x 處于等待態,Promise 需保持為等待態直至 x 被執行或拒絕

如果 x 處于其他狀態,則用相同的值處理 Promise

當然以上這些是規范需要我們判斷的情況,實際上我們不判斷狀態也是可行的。

接下來我們繼續按照規范來實現剩余的代碼

let called = false
if (x !== null && (typeof x === "object" || typeof x === "function")) {
  try {
    let then = x.then
    if (typeof then === "function") {
      then.call(
        x,
        y => {
          if (called) return
          called = true
          resolutionProcedure(promise2, y, resolve, reject)
        },
        e => {
          if (called) return
          called = true
          reject(e)
        }
      )
    } else {
      resolve(x)
    }
  } catch (e) {
    if (called) return
    called = true
    reject(e)
  }
} else {
  resolve(x)
}

首先創建一個變量 called 用于判斷是否已經調用過函數

然后判斷 x 是否為對象或者函數,如果都不是的話,將 x 傳入 resolve

如果 x 是對象或者函數的話,先把 x.then 賦值給 then,然后判斷 then 的類型,如果不是函數類型的話,就將 x 傳入 resolve

如果 then 是函數類型的話,就將 x 作為函數的作用域 this 調用之,并且傳遞兩個回調函數作為參數,第一個參數叫做 resolvePromise ,第二個參數叫做 rejectPromise,兩個回調函數都需要判斷是否已經執行過函數,然后進行相應的邏輯

以上代碼在執行的過程中如果拋錯了,將錯誤傳入 reject 函數中

以上就是符合 Promise/A+ 規范的實現

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102016.html

相關文章

  • 前端從零開始系列

    摘要:只有動手,你才能真的理解作者的構思的巧妙只有動手,你才能真正掌握一門技術持續更新中項目地址求求求源碼系列跟一起學如何寫函數庫中高級前端面試手寫代碼無敵秘籍如何用不到行代碼寫一款屬于自己的類庫原理講解實現一個對象遵循規范實戰手摸手,帶你用擼 Do it yourself!!! 只有動手,你才能真的理解作者的構思的巧妙 只有動手,你才能真正掌握一門技術 持續更新中…… 項目地址 https...

    Youngdze 評論0 收藏0
  • 「中高級前端面試」JavaScript手寫代碼無敵秘籍

    摘要:第一種直接調用避免在不必要的情況下使用,是一個危險的函數,他執行的代碼擁有著執行者的權利。來自于此外,實現需要考慮實例化后對原型鏈的影響。函數柯里化的主要作用和特點就是參數復用提前返回和延遲執行。手寫路徑導航 實現一個new操作符 實現一個JSON.stringify 實現一個JSON.parse 實現一個call或 apply 實現一個Function.bind 實現一個繼承 實現一個J...

    Zhuxy 評論0 收藏0
  • 22道JavaScript高頻手寫面試題

    JavaScript筆試部分 點擊關注本公眾號獲取文檔最新更新,并可以領取配套于本指南的 《前端面試手冊》 以及最標準的簡歷模板. 實現防抖函數(debounce) 防抖函數原理:在事件被觸發n秒后再執行回調,如果在這n秒內又被觸發,則重新計時。 那么與節流函數的區別直接看這個動畫實現即可。 showImg(https://segmentfault.com/img/remote/146000002...

    Alan 評論0 收藏0
  • 2019-我的前端面試題

    摘要:先說下我面試情況,我一共面試了家公司。篇在我面試的眾多公司里,只有同城的面問到相關問題,其他公司壓根沒問。我自己回答的是自己開發組件面臨的問題。完全不用擔心對方到時候打電話核對的問題。 2019的5月9號,離發工資還有1天的時候,我的領導親切把我叫到辦公室跟我說:阿郭,我們公司要倒閉了,錢是沒有的啦,為了不耽誤你,你趕緊出去找工作吧。聽到這話,我虎軀一震,這已經是第2個月沒工資了。 公...

    iKcamp 評論0 收藏0
  • What's New in JavaScript

    摘要:在和中都保留了數組的強引用,所以在中簡單的清除變量內存并沒有得到釋放,因為還存在引用計數。而在中,它的鍵是弱引用,不計入引用計數中,所以當被清除之后,數組會因為引用計數為而被回收掉。其實我們主要注意的引用是不計引用計數的,就好理解了。 showImg(https://segmentfault.com/img/remote/1460000019147368?w=900&h=383); 前...

    cgh1999520 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<