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

資訊專欄INFORMATION COLUMN

從0開始構(gòu)建自己的前端知識(shí)體系-JS-跟著規(guī)范學(xué)Promise

kelvinlee / 2627人閱讀

摘要:本文僅限瀏覽器環(huán)境測(cè)試,環(huán)境可能會(huì)不一致狀態(tài)一個(gè)實(shí)例只能處于三種狀態(tài)中的一種。每次創(chuàng)建的實(shí)例都會(huì)處于狀態(tài),并且只能由變?yōu)榛驙顟B(tài)??梢哉J(rèn)為在實(shí)現(xiàn)里與中的都為解決程序。

前言

Promise作為ES6極為重要的一個(gè)特性,將我們從無(wú)限的回調(diào)地獄中解脫出來(lái),變?yōu)殒準(zhǔn)降木帉懟卣{(diào),大大提高的代碼的可讀性。

使用Promise是極為簡(jiǎn)單的,但只停留在會(huì)使用階段還是會(huì)讓我們不知不覺(jué)踩到一些坑的。本文會(huì)結(jié)合Promise/A+規(guī)范與示例來(lái)深入學(xué)習(xí)Promise

本文較長(zhǎng),例子很多,末尾有一些應(yīng)用 ^_^

Promise

兼容性

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

作用

js是單線程的,異步是通過(guò)Event Loop來(lái)實(shí)現(xiàn)的,那么需要一種更加友好的方式來(lái)實(shí)現(xiàn)我們的異步操作,而不是無(wú)限的回調(diào)嵌套

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

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

}).then(() => {

}).then(() => {

}).then(() => {

})

API

先來(lái)簡(jiǎn)單看一下Promise提供的一些API(注意區(qū)分靜態(tài)方法與實(shí)例方法)

構(gòu)造函數(shù)Promise

Promise是一個(gè)構(gòu)造函數(shù),可以通過(guò)new操作符來(lái)創(chuàng)建一個(gè)Promise實(shí)例

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

靜態(tài)方法

Promise.resolve

Promise.reject

Promise.all

Promise.race

實(shí)例方法

Promise.prototype.then

Promise.prototype.catch

結(jié)合規(guī)范與樣例

規(guī)范

官方英文原版規(guī)范

tips:

規(guī)范是規(guī)范,實(shí)現(xiàn)是實(shí)現(xiàn),實(shí)現(xiàn)是按照規(guī)范來(lái)實(shí)現(xiàn)的,但不一定完全等同于規(guī)范。

本文僅限瀏覽器環(huán)境測(cè)試,node環(huán)境可能會(huì)不一致

狀態(tài)

一個(gè)Promise實(shí)例只能處于pending,fulfilled,rejected三種狀態(tài)中的一種。每次創(chuàng)建的promise實(shí)例都會(huì)處于pending狀態(tài),并且只能由pending變?yōu)?b>fulfilled或reject狀態(tài)。一旦處于fulfilledrejected狀態(tài)無(wú)論進(jìn)行什么操作都不會(huì)再次變更狀態(tài)(規(guī)范2.1)

// 創(chuàng)建一個(gè)處于pending狀態(tài)的promise實(shí)例
let promise1 = new Promise((resolve, reject) => {

})

// 調(diào)用resolve()會(huì)使promise從pending狀態(tài)變?yōu)閒ulfilled狀態(tài)
let promise2 = new Promise((resolve, reject) => {
  resolve(1)
})

// 調(diào)用reject()會(huì)使promise從pending狀態(tài)變?yōu)閞ejected狀態(tài)
let promise3 = new Promise((resolve, reject) => {
  reject(1)
})

// 無(wú)論如何更改resolve與reject的執(zhí)行順序,promise4始終只會(huì)處于先調(diào)用后轉(zhuǎn)換的狀態(tài)(狀態(tài)一旦變?yōu)閒ulfilled或rejected后不會(huì)再次改變)
let promise4 = new Promise((resolve, reject) => {
  resolve(1)
  reject(1)
})

then

參數(shù)

實(shí)例方法then的回調(diào)函數(shù)接受兩個(gè)參數(shù),onFulfilledonRejected,都為可選參數(shù)(規(guī)范2.2.1)

// onFulfilled會(huì)在狀態(tài)變?yōu)閒ulfilled后調(diào)用,onFulfilled參數(shù)value為resolve的第一個(gè)參數(shù),onRejected同理。(規(guī)范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) => {

})

// 可被同一個(gè)promise多次調(diào)用(規(guī)范2.2.6)
promise.then()

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

返回值

then方法必須返回一個(gè)promise實(shí)例(規(guī)范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```返回了一個(gè)value ```x```,運(yùn)行promise解決程序(下一節(jié)), [[Resolve]](promise2, x) (規(guī)范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```拋出了一個(gè)exception ```e```, ```promise2```必須以e作為reason rejected (規(guī)范2.2.7.2)
// 故下方a2 b2 都為狀態(tài)是rejected的promise實(shí)例
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狀態(tài)并且onFulfilled不是一個(gè)函數(shù),那么promise2會(huì)以與promise1具有相同value和相同的狀態(tài), 但是與promise1并不是同一Promise實(shí)例;若為rejected狀態(tài)以此類推
var a3 = a.then()
a3 === a // false
var b3 = b.then()
b3 === b // false

解決程序resolve

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

可以認(rèn)為在實(shí)現(xiàn)里Promise.resolve()new Promise((resolve, reject) => {})中的resolve都為解決程序。規(guī)范中x對(duì)應(yīng)實(shí)現(xiàn)中resolve的第一個(gè)參數(shù),規(guī)范中promise在實(shí)現(xiàn)中等價(jià)于當(dāng)前promise

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

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)
})

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

c1 === c // false

// pending狀態(tài)下的,只要e狀態(tài)變?yōu)椋琫1也會(huì)改變(規(guī)范2.3.2.1) 
var e1 = Promise.resolve().then(function onFulfilled () {
  return e
})

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

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

// 如果x是thenable 但x.then不是一個(gè)函數(shù)或者對(duì)象,直接返回狀態(tài)為fulfilled,value為x的promise實(shí)例(規(guī)范2.3.3.4)
var c4 = c1.then(function onFulfilled () {
  return {}
})

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

// 如果x是thenable 并且x.then是一個(gè)函數(shù),那么就會(huì)調(diào)用這個(gè)then方法執(zhí)行,并且兩個(gè)參數(shù)resolve與reject擁有改變返回的promise狀態(tài)的權(quán)利,會(huì)按解決程序處理,如果不調(diào)用兩個(gè)參數(shù)方法,則返回的promise為pending狀態(tài),值得一提的是,調(diào)用then方法的時(shí)候回以返回對(duì)象x作為then的this綁定調(diào)用(規(guī)范 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狀態(tài)的promise
var c9 = c1.then(function onFulfilled () {
  return {
    then: function () {}
  }
})

// 如果x不是對(duì)象也不是函數(shù),則返回狀態(tài)為fulfilled的promise,value為x

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

綜上可以總結(jié)幾點(diǎn)

1.  ```new Promise, promise.then, Promise.resolve()```都會(huì)返回promise實(shí)例
2.  Promise狀態(tài)一旦改變不可再更改
3.  ```then```方法返回對(duì)象的不同會(huì)導(dǎo)致不同的結(jié)果,如果意外返回了thenable有可能會(huì)造成意想不到的結(jié)果
應(yīng)用

封裝一個(gè)異步請(qǐng)求

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)
})

同時(shí)請(qǐng)求按序處理

// 假設(shè)有5個(gè)章節(jié)的數(shù)據(jù),我們需要分別獲取并讀取到c中,利用promise和es6數(shù)組api我們可以寫出簡(jiǎn)潔優(yōu)雅的代碼完成這個(gè)需求

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

var getData = function (key) {
  return new Promise((resolve, reject) => {
    // 模擬一些返回時(shí)間不相同的異步操作
    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

明明在我們?nèi)粘9ぷ髦谐S玫降腸atch方法,為什么到現(xiàn)在還一點(diǎn)都沒(méi)有提到呢?

因?yàn)閏atch方法就是then方法封裝出來(lái)的語(yǔ)法糖而已,因?yàn)槿绻幌氩东@錯(cuò)誤,還每次都要書寫then的第一個(gè)參數(shù),真的是麻煩至極,現(xiàn)在我們來(lái)寫一個(gè)自己的catch

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

// 用到了規(guī)范中如果onFulfilled不是一個(gè)函數(shù),則忽略,并使用原先promise狀態(tài)與value

finally

有的瀏覽器實(shí)現(xiàn)了finally,而有的并沒(méi)有,從需求上來(lái)講finally只不過(guò)是最終要執(zhí)行一個(gè)函數(shù),我們需要把應(yīng)該有的狀態(tài)或者異常都繼續(xù)傳遞,不受其影響。執(zhí)行的函數(shù)與promise的value無(wú)任何關(guān)系

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
    })
  })
}

后記

通過(guò)閱讀規(guī)范并寫demo進(jìn)行驗(yàn)證測(cè)試,對(duì)Promise的理解更加深入了,也能更好的使用它了
如果喜歡可以star一下,會(huì)不斷更新github地址

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/94387.html

相關(guān)文章

  • 【全文】狼叔:如何正確學(xué)習(xí)Node.js

    摘要:感謝大神的免費(fèi)的計(jì)算機(jī)編程類中文書籍收錄并推薦地址,以后在倉(cāng)庫(kù)里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡(jiǎn)介現(xiàn)在,越來(lái)越多的科技公司和開發(fā)者開始使用開發(fā)各種應(yīng)用。 說(shuō)明 2017-12-14 我發(fā)了一篇文章《沒(méi)用過(guò)Node.js,就別瞎逼逼》是因?yàn)橛腥嗽谥跎虾贜ode.js。那篇文章的反響還是相當(dāng)不錯(cuò)的,甚至連著名的hax賀老都很認(rèn)同,下班時(shí)讀那篇文章,竟然坐車的還坐過(guò)站了。大家可以很...

    Edison 評(píng)論0 收藏0
  • 【全文】狼叔:如何正確學(xué)習(xí)Node.js

    摘要:感謝大神的免費(fèi)的計(jì)算機(jī)編程類中文書籍收錄并推薦地址,以后在倉(cāng)庫(kù)里更新地址,聲音版全文狼叔如何正確的學(xué)習(xí)簡(jiǎn)介現(xiàn)在,越來(lái)越多的科技公司和開發(fā)者開始使用開發(fā)各種應(yīng)用。 說(shuō)明 2017-12-14 我發(fā)了一篇文章《沒(méi)用過(guò)Node.js,就別瞎逼逼》是因?yàn)橛腥嗽谥跎虾贜ode.js。那篇文章的反響還是相當(dāng)不錯(cuò)的,甚至連著名的hax賀老都很認(rèn)同,下班時(shí)讀那篇文章,竟然坐車的還坐過(guò)站了。大家可以很...

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

    摘要:在他的重學(xué)前端課程中提到到現(xiàn)在為止,前端工程師已經(jīng)成為研發(fā)體系中的重要崗位之一。大部分前端工程師的知識(shí),其實(shí)都是來(lái)自于實(shí)踐和工作中零散的學(xué)習(xí)。一基礎(chǔ)前端工程師吃飯的家伙,深度廣度一樣都不能差。 開篇 前端開發(fā)是一個(gè)非常特殊的行業(yè),它的歷史實(shí)際上不是很長(zhǎng),但是知識(shí)之繁雜,技術(shù)迭代速度之快是其他技術(shù)所不能比擬的。 winter在他的《重學(xué)前端》課程中提到: 到現(xiàn)在為止,前端工程師已經(jīng)成為研...

    羅志環(huán) 評(píng)論0 收藏0
  • 一名【合格】前端工程師自檢清單

    摘要:在他的重學(xué)前端課程中提到到現(xiàn)在為止,前端工程師已經(jīng)成為研發(fā)體系中的重要崗位之一。大部分前端工程師的知識(shí),其實(shí)都是來(lái)自于實(shí)踐和工作中零散的學(xué)習(xí)。一基礎(chǔ)前端工程師吃飯的家伙,深度廣度一樣都不能差。開篇 前端開發(fā)是一個(gè)非常特殊的行業(yè),它的歷史實(shí)際上不是很長(zhǎng),但是知識(shí)之繁雜,技術(shù)迭代速度之快是其他技術(shù)所不能比擬的。 winter在他的《重學(xué)前端》課程中提到: 到現(xiàn)在為止,前端工程師已經(jīng)成為研發(fā)體系...

    isaced 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<