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

資訊專欄INFORMATION COLUMN

從0開始構建自己的前端知識體系-JS-跟著規范學Promise

kelvinlee / 2635人閱讀

摘要:本文僅限瀏覽器環境測試,環境可能會不一致狀態一個實例只能處于三種狀態中的一種。每次創建的實例都會處于狀態,并且只能由變為或狀態。可以認為在實現里與中的都為解決程序。

前言

Promise作為ES6極為重要的一個特性,將我們從無限的回調地獄中解脫出來,變為鏈式的編寫回調,大大提高的代碼的可讀性。

使用Promise是極為簡單的,但只停留在會使用階段還是會讓我們不知不覺踩到一些坑的。本文會結合Promise/A+規范與示例來深入學習Promise

本文較長,例子很多,末尾有一些應用 ^_^

Promise

兼容性

Promise作為是瀏覽器的內置函數對象,除IE不支持外所有主流版本的瀏覽器都是支持的,如不需支持IE可以在不引入polyfill的情況下放心食用

作用

js是單線程的,異步是通過Event Loop來實現的,那么需要一種更加友好的方式來實現我們的異步操作,而不是無限的回調嵌套

// no promise
callback(() => {
  callback(() => {
    callback(() => {
      ...
    })
  })
})

// with promise
new Promise((resolve, reject) => {

}).then(() => {

}).then(() => {

}).then(() => {

})

API

先來簡單看一下Promise提供的一些API(注意區分靜態方法與實例方法)

構造函數Promise

Promise是一個構造函數,可以通過new操作符來創建一個Promise實例

let promise = new Promise((resolve, reject) => {
  resolve(1)
})

靜態方法

Promise.resolve

Promise.reject

Promise.all

Promise.race

實例方法

Promise.prototype.then

Promise.prototype.catch

結合規范與樣例

規范

官方英文原版規范

tips:

規范是規范,實現是實現,實現是按照規范來實現的,但不一定完全等同于規范。

本文僅限瀏覽器環境測試,node環境可能會不一致

狀態

一個Promise實例只能處于pending,fulfilled,rejected三種狀態中的一種。每次創建的promise實例都會處于pending狀態,并且只能由pending變為fulfilledreject狀態。一旦處于fulfilledrejected狀態無論進行什么操作都不會再次變更狀態(規范2.1)

// 創建一個處于pending狀態的promise實例
let promise1 = new Promise((resolve, reject) => {

})

// 調用resolve()會使promise從pending狀態變為fulfilled狀態
let promise2 = new Promise((resolve, reject) => {
  resolve(1)
})

// 調用reject()會使promise從pending狀態變為rejected狀態
let promise3 = new Promise((resolve, reject) => {
  reject(1)
})

// 無論如何更改resolve與reject的執行順序,promise4始終只會處于先調用后轉換的狀態(狀態一旦變為fulfilled或rejected后不會再次改變)
let promise4 = new Promise((resolve, reject) => {
  resolve(1)
  reject(1)
})

then

參數

實例方法then的回調函數接受兩個參數,onFulfilledonRejected,都為可選參數(規范2.2.1)

// onFulfilled會在狀態變為fulfilled后調用,onFulfilled參數value為resolve的第一個參數,onRejected同理。(規范2.2.2與2.2.3)

let promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1)
  }, 1000) 
})

promise.then((value) => {
  console.log(value)  // 1秒后輸出1
}, (reason) => {

})

// 可被同一個promise多次調用(規范2.2.6)
promise.then()

promise.then((value) => {
  console.log(value) // 1秒后輸出1
})

返回值

then方法必須返回一個promise實例(規范2.2.7)

假定 promise2 = promise1.then(onFulfilled, onRejected)

var a = new Promise((resolve, reject) => {
  resolve(1)
})

var b = new Promise((resolve, reject) => {
  reject(1)
})

// 如果```onFulfilled```或```onRejected```返回了一個value ```x```,運行promise解決程序(下一節), [[Resolve]](promise2, x) (規范2.2.7.1)
var a1 = a.then(function onFulfilled(value) {
  return 1
}, function onRejected (reason) {

})

var b1 = b.then(function onFulfilled(value) {
  
}, function onRejected (reason) {
  return 1
})

// 如果```onFulfilled```或```onRejected```拋出了一個exception ```e```, ```promise2```必須以e作為reason rejected (規范2.2.7.2)
// 故下方a2 b2 都為狀態是rejected的promise實例
var a2 = a.then(function onFulfilled(value) {
  throw Error("test")
}, function onRejected (reason) {

})

var b2 = b.then(function onFulfilled(value) {
  
}, function onRejected (reason) {
  throw Error("test")
})

// 如果promise1處于fulfilled狀態并且onFulfilled不是一個函數,那么promise2會以與promise1具有相同value和相同的狀態, 但是與promise1并不是同一Promise實例;若為rejected狀態以此類推
var a3 = a.then()
a3 === a // false
var b3 = b.then()
b3 === b // false

解決程序resolve

在規范中, promise解決程序是一個以promisevalue作為輸入的抽象操作,我們表示為[[Resolve]](promise, x)

可以認為在實現里Promise.resolve()new Promise((resolve, reject) => {})中的resolve都為解決程序。規范中x對應實現中resolve的第一個參數,規范中promise在實現中等價于當前promise

可以理解為Promise.resolve(x)new Promise(resolve) => {resolve(x)}等價

var c = new Promise((resolve, reject) => {
  resolve(1)
})

var d = new Promise((resolve, reject) => {
  reject(1)
})

var e = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("5s后resolve")
  }, 5000)
})

// 在返回值章節我們了解到,onFulfilled如果為函數在不拋出錯誤的情況下,會調用解決程序處理返回值x
// 如果x是promise, 采納他的狀態(注意,但then的返回值并不與x相等)(規范2.3.2)
var c1 = Promise.resolve().then(function onFulfilled() {
  return c
})

c1 === c // false

// pending狀態下的,只要e狀態變為,e1也會改變(規范2.3.2.1) 
var e1 = Promise.resolve().then(function onFulfilled () {
  return e
})

var c2 = Promise.resolve()
// 如果promise和x是相同的對象, 使用TypeError作為reason reject promise(規范2.3.1)
var c3 = c2.then(function onFulfilled () {
  return c3
})

概念:如果一個函數或者對象具有then屬性,那么叫做thenable(例: { then: function(){} })

// 如果x是thenable 但x.then不是一個函數或者對象,直接返回狀態為fulfilled,value為x的promise實例(規范2.3.3.4)
var c4 = c1.then(function onFulfilled () {
  return {}
})

var c5 = c1.then(function onFulfilled () {
  return {
    then: 2
  }
})

// 如果x是thenable 并且x.then是一個函數,那么就會調用這個then方法執行,并且兩個參數resolve與reject擁有改變返回的promise狀態的權利,會按解決程序處理,如果不調用兩個參數方法,則返回的promise為pending狀態,值得一提的是,調用then方法的時候回以返回對象x作為then的this綁定調用(規范 2.3.3.3)

var c6 = c1.then(function onFulfilled () {
  return {
    test: "test",
    then: function (resolve, reject) {
      console.log(this.test)
      resolve("thenable")
    }
  }
})

var c7 = c1.then(function onFulfilled () {
  function x () {}
  x.test = "test"
  x.then = function (resolve, reject) {
    console.log(this.test)
    resolve("thenable")
  }
  return x
})

var c8 = c1.then(function onFulfilled () {
  return {
    test: "test",
    then: function (resolve, reject) {
      console.log(this.test)
      reject("thenable")
    }
  }
})

// 返回pending狀態的promise
var c9 = c1.then(function onFulfilled () {
  return {
    then: function () {}
  }
})

// 如果x不是對象也不是函數,則返回狀態為fulfilled的promise,value為x

var c10 = c1.then(function onFulfilled () {
  return "hehe"
})

綜上可以總結幾點

1.  ```new Promise, promise.then, Promise.resolve()```都會返回promise實例
2.  Promise狀態一旦改變不可再更改
3.  ```then```方法返回對象的不同會導致不同的結果,如果意外返回了thenable有可能會造成意想不到的結果
應用

封裝一個異步請求

var promiseXHR = new Promise((resolve, reject) => {
  var xhr = new XMLHttpRequest()
  xhr.open("GET", "http://www.baidu.com", true)
  xhr.onreadystatechange = function () {
    if (xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
      resolve(xhr.response)
    } else {
      reject()
    }
  }
  xhr.send(data)
})

同時請求按序處理

// 假設有5個章節的數據,我們需要分別獲取并讀取到c中,利用promise和es6數組api我們可以寫出簡潔優雅的代碼完成這個需求

var list = ["Chapter1", "Chapter2", "Chapter3", "Chapter4", "Chapter5"]

var getData = function (key) {
  return new Promise((resolve, reject) => {
    // 模擬一些返回時間不相同的異步操作
    setTimeout(() => {
      resolve(key)
    }, 4000 * Math.random())
  })
}

var c = ""

list.map(i => getData(i))
    .reduce((accumulator, current) => {
      console.log(accumulator)
      return accumulator.then(() => {
        return current
      }).then(value => {
        c+= value
      })
    }, Promise.resolve(""))

catch

明明在我們日常工作中常用到的catch方法,為什么到現在還一點都沒有提到呢?

因為catch方法就是then方法封裝出來的語法糖而已,因為如果只想捕獲錯誤,還每次都要書寫then的第一個參數,真的是麻煩至極,現在我們來寫一個自己的catch

Promise.prototype.mycatch = function (cb) {
    return this.then(1, function onRejected (reason) {
      return cb(reason)
    })
  }

// 用到了規范中如果onFulfilled不是一個函數,則忽略,并使用原先promise狀態與value

finally

有的瀏覽器實現了finally,而有的并沒有,從需求上來講finally只不過是最終要執行一個函數,我們需要把應該有的狀態或者異常都繼續傳遞,不受其影響。執行的函數與promise的value無任何關系

Promise.prototype.myfinally = function (cb) {
  return this.then(function onFulfilled (value) {
    return Promise.resolve(cb()).then(() => value)
  }, function onRejected (reason) {
    return Promise.resolve(cb()).then(() => {
      throw reason
    })
  })
}

后記

通過閱讀規范并寫demo進行驗證測試,對Promise的理解更加深入了,也能更好的使用它了
如果喜歡可以star一下,會不斷更新github地址

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

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

相關文章

  • 【全文】狼叔:如何正確習Node.js

    摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學習簡介現在,越來越多的科技公司和開發者開始使用開發各種應用。 說明 2017-12-14 我發了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當不錯的,甚至連著名的hax賀老都很認同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...

    Edison 評論0 收藏0
  • 【全文】狼叔:如何正確習Node.js

    摘要:感謝大神的免費的計算機編程類中文書籍收錄并推薦地址,以后在倉庫里更新地址,聲音版全文狼叔如何正確的學習簡介現在,越來越多的科技公司和開發者開始使用開發各種應用。 說明 2017-12-14 我發了一篇文章《沒用過Node.js,就別瞎逼逼》是因為有人在知乎上黑Node.js。那篇文章的反響還是相當不錯的,甚至連著名的hax賀老都很認同,下班時讀那篇文章,竟然坐車的還坐過站了。大家可以很...

    fengxiuping 評論0 收藏0
  • 一名【合格】前端工程師自檢清單

    摘要:在他的重學前端課程中提到到現在為止,前端工程師已經成為研發體系中的重要崗位之一。大部分前端工程師的知識,其實都是來自于實踐和工作中零散的學習。一基礎前端工程師吃飯的家伙,深度廣度一樣都不能差。 開篇 前端開發是一個非常特殊的行業,它的歷史實際上不是很長,但是知識之繁雜,技術迭代速度之快是其他技術所不能比擬的。 winter在他的《重學前端》課程中提到: 到現在為止,前端工程師已經成為研...

    羅志環 評論0 收藏0
  • 一名【合格】前端工程師自檢清單

    摘要:在他的重學前端課程中提到到現在為止,前端工程師已經成為研發體系中的重要崗位之一。大部分前端工程師的知識,其實都是來自于實踐和工作中零散的學習。一基礎前端工程師吃飯的家伙,深度廣度一樣都不能差。開篇 前端開發是一個非常特殊的行業,它的歷史實際上不是很長,但是知識之繁雜,技術迭代速度之快是其他技術所不能比擬的。 winter在他的《重學前端》課程中提到: 到現在為止,前端工程師已經成為研發體系...

    isaced 評論0 收藏0

發表評論

0條評論

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