成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JS 異步系列 —— Promise 札記

zhouzhou / 2250人閱讀

摘要:以下,請(qǐng)求兩個(gè),當(dāng)兩個(gè)異步請(qǐng)求返還結(jié)果后,再請(qǐng)求第三個(gè)此處為調(diào)用后的結(jié)果的數(shù)組對(duì)于來說,只要參數(shù)數(shù)組有一個(gè)元素變?yōu)闆Q定態(tài),便返回新的。

Promise 札記

研究 Promise 的動(dòng)機(jī)大體有以下幾點(diǎn):

對(duì)其 api 的不熟悉以及對(duì)實(shí)現(xiàn)機(jī)制的好奇;

很多庫(比如 fetch)是基于 Promise 封裝的,那么要了解這些庫的前置條件得先熟悉 Promise;

要了解其它更為高級(jí)的異步操作得先熟悉 Promise;

基于這些目的,實(shí)踐了一個(gè)符合 Promise/A+ 規(guī)范的 repromise

本札記系列總共三篇文章,作為之前的文章 Node.js 異步異聞錄 的拆分和矯正。

Promise札記

Generator札記

Async札記

Promise/A+ 核心

在實(shí)現(xiàn)一個(gè)符合 Promise/A+ 規(guī)范的 promise 之前,先了解下 Promise/A+ 核心,想更全面地了解可以閱讀 Promise/A+規(guī)范

Promise 操作只會(huì)處在 3 種狀態(tài)的一種:未完成態(tài)(pending)、完成態(tài)(resolved) 和失敗態(tài)(rejected);

Promise 的狀態(tài)只會(huì)出現(xiàn)從未完成態(tài)向完成態(tài)或失敗態(tài)轉(zhuǎn)化;

Promise 的狀態(tài)一旦轉(zhuǎn)化,將不能被更改;

repromise api 食用手冊(cè) Promise.resolve()

Promise.resolve() 括號(hào)內(nèi)有 4 種情況

/* 跟 Promise 對(duì)象 */
Promise.resolve(Promise.resolve(1))
// Promise?{state: "resolved", data: 1, callbackQueue: Array(0)}

/* 跟 thenable 對(duì)象 */
var thenable = {
  then: function(resolve, reject) {
    resolve(1)
  }
}

Promise.resolve(thenable)
// Promise?{state: "resolved", data: 1, callbackQueue: Array(0)}

/* 普通參數(shù) */
Promise.resolve(1)
// Promise?{state: "resolved", data: 1, callbackQueue: Array(0)}

/* 不跟參數(shù) */
Promise.resolve()
// Promise?{state: "resolved", data: undefined, callbackQueue: Array(0)}
Promise.reject()

相較于 Promise.resolve(),Promise.reject() 原封不動(dòng)地返回參數(shù)值

Promise.all(arr)

對(duì)于 Promise.all(arr) 來說,在參數(shù)數(shù)組中所有元素都變?yōu)闆Q定態(tài)后,然后才返回新的 promise。

// 以下 demo,請(qǐng)求兩個(gè) url,當(dāng)兩個(gè)異步請(qǐng)求返還結(jié)果后,再請(qǐng)求第三個(gè) url
const p1 = request(`http://some.url.1`)
const p2 = request(`http://some.url.2`)

Promise.all([p1, p2])
  .then((datas) => { // 此處 datas 為調(diào)用 p1, p2 后的結(jié)果的數(shù)組
    return request(`http://some.url.3?a=${datas[0]}&b=${datas[1]}`)
  })
  .then((data) => {
    console.log(msg)
  })
Promise.race(arr)

對(duì)于 Promise.race(arr) 來說,只要參數(shù)數(shù)組有一個(gè)元素變?yōu)闆Q定態(tài),便返回新的 promise。

// race 譯為競(jìng)爭,同樣是請(qǐng)求兩個(gè) url,當(dāng)且僅當(dāng)一個(gè)請(qǐng)求返還結(jié)果后,就請(qǐng)求第三個(gè) url
const p1 = request(`http://some.url.1`)
const p2 = request(`http://some.url.2`)

Promise.race([p1, p2])
  .then((data) => { // 此處 data 取調(diào)用 p1, p2 后優(yōu)先返回的結(jié)果
    return request(`http://some.url.3?value=${data}`)
  })
  .then((data) => {
    console.log(data)
  })
Promise.wrap(fn) —— 回調(diào)函數(shù)轉(zhuǎn) Promise

通過下面這個(gè)案例,提供回調(diào)函數(shù) Promise 化的思路。

function foo(a, b, cb) {
  ajax(
    `http://some.url?a=${a}&b=$`,
    cb
  )
}

foo(1, 2, function(err, data) {
  if (err) {
    console.log(err)
  } else {
    console.log(data)
  }
})

如上是一個(gè)傳統(tǒng)回調(diào)函數(shù)使用案例,只要使用 Promise.wrap() 包裹 foo 函數(shù)就對(duì)其完成了 promise 化,使用如下:

const promiseFoo = Promise.wrap(foo)

promiseFoo(1, 2)
  .then((data) => {
    console.log(data)
  })
  .catch((err) => {
    console.log(err)
  })

Promise.wrap 的實(shí)現(xiàn)邏輯也順帶列出來了:

Promise.wrap = function(fn) {
  return funtion() {
    const args = [].slice.call(arguments)
    return new Promise((resolve, reject) => {
      fn.apply(null, args.concat((err, data) => {
        if (err) {
          reject(err)
        } else {
          resolve(data)
        }
      }))
    })
  }
}
then/catch/done

這幾個(gè) api 比較簡單,合起來一起帶過

Promise.resolve(1)
  .then((data) => {console.log(data)}, (err) => {console.log(err)}) // 鏈?zhǔn)秸{(diào)用,可以傳一個(gè)參數(shù)(推薦),也可以傳兩個(gè)參數(shù)
  .catch((err) => {console.log(err)}) // 捕獲鏈?zhǔn)秸{(diào)用中拋出的錯(cuò)誤 || 捕獲變?yōu)槭B(tài)的值
  .done()                             // 能捕獲前面鏈?zhǔn)秸{(diào)用的錯(cuò)誤(包括 catch 中),可以傳兩個(gè)參數(shù)也可不傳
實(shí)踐過程總結(jié) 坑點(diǎn) 1:事件循環(huán)
事件循環(huán):同步隊(duì)列執(zhí)行完后,在指定時(shí)間后再執(zhí)行異步隊(duì)列的內(nèi)容。

之所以要單列事件循環(huán),因?yàn)榇a的執(zhí)行順序與其息息相關(guān),此處用 setTimeout 來模擬事件循環(huán);

下面代碼片段中,① 處執(zhí)行完并不會(huì)馬上執(zhí)行 setTimeout() 中的代碼(③),而是此時(shí)有多少次 then 的調(diào)用,就會(huì)重新進(jìn)入 ② 處多少次后,再進(jìn)入 ③

excuteAsyncCallback(callback, value) {
  const that = this
  setTimeout(function() {
    const res = callback(value) // ③
    that.excuteCallback("fulfilled", res)
  }, 4)
}

then(onResolved, onRejected) {
  const promise = new this.constructor()
  if (this.state !== "PENDING") {
    const callback = this.state === "fulfilled" ? onResolved : onRejected
    this.excuteAsyncCallback.call(promise, callback, this.data)              // ①
  } else {
    this.callbackArr.push(new CallbackItem(promise, onResolved, onRejected)) // ②
  }
  return promise
}
坑點(diǎn) 2:this 的指向問題

this.callbackArr.push() 中的 this 指向的是 ‘上一個(gè)’ promise,所以類 CallbackItem 中,this.promise 存儲(chǔ)的是"下一個(gè)" promise(then 對(duì)象)。

class Promise {
  ...
  then(onResolved, onRejected) {
    const promise = new this.constructor()
    if (this.state !== "PENDING") {        // 第一次進(jìn)入 then,狀態(tài)是 RESOLVED 或者是 REJECTED
      const callback = this.state === "fulfilled" ? onResolved : onRejected
      this.excuteAsyncCallback.call(promise, callback, this.data)  // 綁定 this 到 promise
    } else {                               // 從第二次開始以后,進(jìn)入 then,狀態(tài)是 PENDING
      this.callbackArr.push(new CallbackItem(promise, onResolved, onRejected)) // 這里的 this 也是指向‘上一個(gè)’ promise
    }
    return promise
  }
  ...
}

class CallbackItem {
  constructor(promise, onResolve, onReject) {
    this.promise = promise // 相應(yīng)地,這里存儲(chǔ)的 promise 是來自下一個(gè) then 的
    this.onResolve = typeof(onResolve) === "function" ? onResolve : (resolve) => {}
    this.onReject = typeof(onRejected) === "function" ? onRejected : (rejected) => {}
  }
  ...
}
more

實(shí)踐的更多過程可以參考測(cè)試用例。有好的意見歡迎交流。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/95850.html

相關(guān)文章

  • ES6常用知識(shí)學(xué)習(xí)札記

    摘要:在年正式發(fā)布了,簡稱,又稱為。再次簡寫循環(huán)迭代數(shù)組每個(gè)元素都執(zhí)行一次回調(diào)函數(shù)。方法用于調(diào)用數(shù)組的每個(gè)元素,并將元素傳遞給回調(diào)函數(shù)。注意對(duì)于空數(shù)組是不會(huì)執(zhí)行回調(diào)函數(shù)的。 轉(zhuǎn)載請(qǐng)注明出處 原文連接 http://blog.huanghanlian.com/article/5c7aa6c7bf3acc0864870f9d es6 是什么 首先弄明白ECMA和js的關(guān)系。ECMA是標(biāo)準(zhǔn),Jav...

    googollee 評(píng)論0 收藏0
  • ES6常用知識(shí)學(xué)習(xí)札記

    摘要:在年正式發(fā)布了,簡稱,又稱為。再次簡寫循環(huán)迭代數(shù)組每個(gè)元素都執(zhí)行一次回調(diào)函數(shù)。方法用于調(diào)用數(shù)組的每個(gè)元素,并將元素傳遞給回調(diào)函數(shù)。注意對(duì)于空數(shù)組是不會(huì)執(zhí)行回調(diào)函數(shù)的。 轉(zhuǎn)載請(qǐng)注明出處 原文連接 http://blog.huanghanlian.com/article/5c7aa6c7bf3acc0864870f9d es6 是什么 首先弄明白ECMA和js的關(guān)系。ECMA是標(biāo)準(zhǔn),Jav...

    tracymac7 評(píng)論0 收藏0
  • 前端學(xué)習(xí)札記

    摘要:學(xué)習(xí)工作中遇到的問題,和容易忘記的零碎知識(shí),部分為摘抄,如若侵權(quán),請(qǐng)告知。將構(gòu)造函數(shù)的指向這個(gè)新創(chuàng)建的對(duì)象即將指向這個(gè)新對(duì)象。取消冒泡這種相當(dāng)于全局取消事件冒泡。前端性能的優(yōu)化避免全局查找,全局查找需要涉及作用域鏈上的查找。 學(xué)習(xí)工作中遇到的問題,和容易忘記的零碎知識(shí),部分為摘抄,如若侵權(quán),請(qǐng)告知。 HTML篇 CSS篇 box-sizing: 設(shè)置盒子模型為標(biāo)準(zhǔn)模式或者IE模式。屬性...

    piglei 評(píng)論0 收藏0
  • 前端學(xué)習(xí)札記

    摘要:學(xué)習(xí)工作中遇到的問題,和容易忘記的零碎知識(shí),部分為摘抄,如若侵權(quán),請(qǐng)告知。將構(gòu)造函數(shù)的指向這個(gè)新創(chuàng)建的對(duì)象即將指向這個(gè)新對(duì)象。取消冒泡這種相當(dāng)于全局取消事件冒泡。前端性能的優(yōu)化避免全局查找,全局查找需要涉及作用域鏈上的查找。 學(xué)習(xí)工作中遇到的問題,和容易忘記的零碎知識(shí),部分為摘抄,如若侵權(quán),請(qǐng)告知。 HTML篇 CSS篇 box-sizing: 設(shè)置盒子模型為標(biāo)準(zhǔn)模式或者IE模式。屬性...

    jkyin 評(píng)論0 收藏0
  • 前端學(xué)習(xí)札記

    摘要:學(xué)習(xí)工作中遇到的問題,和容易忘記的零碎知識(shí),部分為摘抄,如若侵權(quán),請(qǐng)告知。將構(gòu)造函數(shù)的指向這個(gè)新創(chuàng)建的對(duì)象即將指向這個(gè)新對(duì)象。取消冒泡這種相當(dāng)于全局取消事件冒泡。前端性能的優(yōu)化避免全局查找,全局查找需要涉及作用域鏈上的查找。 學(xué)習(xí)工作中遇到的問題,和容易忘記的零碎知識(shí),部分為摘抄,如若侵權(quán),請(qǐng)告知。 HTML篇 CSS篇 box-sizing: 設(shè)置盒子模型為標(biāo)準(zhǔn)模式或者IE模式。屬性...

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

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

0條評(píng)論

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