日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

回调地狱解决方案之Promise

發(fā)布時(shí)間:2024/4/13 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 回调地狱解决方案之Promise 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

為什么出現(xiàn)Promise

在javascript開發(fā)過程中,代碼是單線程執(zhí)行的,同步操作,彼此之間不會(huì)等待,這可以說是它的優(yōu)勢(shì),但是也有它的弊端,如一些網(wǎng)絡(luò)操作,瀏覽器事件,文件等操作等,都必須異步執(zhí)行,針對(duì)這些情況,起初的操作都是使用回調(diào)函數(shù)實(shí)現(xiàn)。

實(shí)現(xiàn)方式如下(偽代碼):

function One(callback) {if (success) {callback(err, result);} else {callback(err, null);} } 復(fù)制代碼

One(function (err, result) { //執(zhí)行完One函數(shù)內(nèi)的內(nèi)容,成功的結(jié)果回調(diào)回來向下執(zhí)行 }) 復(fù)制代碼

上述代碼只是一層級(jí)回調(diào),如果代碼復(fù)雜后,會(huì)出現(xiàn)多層級(jí)的回調(diào),代碼可讀性也會(huì)很差,那有沒有一種方式,不用考慮里面的內(nèi)容,直接根據(jù)結(jié)果成功還是失敗執(zhí)行下面的代碼呢?有的,Promise(承諾),在ES6中對(duì)Promise進(jìn)行了同意的規(guī)范。

Promise的含義

  • 書上這么說:

    Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案–回調(diào)函數(shù)和事件--更合理和更強(qiáng)大。它由社區(qū)最早提出和實(shí)現(xiàn),ES6將其寫進(jìn)了語言標(biāo)準(zhǔn),統(tǒng)一了語法,原生提供了Promise

    所謂Promise ,簡(jiǎn)單說就是一個(gè)容器,里面保存著某個(gè)未來才回結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。從語法上說,Promise是一個(gè)對(duì)象,從它可以獲取異步操作的消息。 Promise 對(duì)象的狀態(tài)不受外界影響

  • Promise/a+ 官方網(wǎng)站給出的定義 A promise represents the eventual result of an asyncchronous operation

    翻譯:表示一個(gè)異步操作的最終結(jié)果。

  • 我的理解:

    Promise是回調(diào)函數(shù)可以規(guī)范鏈?zhǔn)?/strong>調(diào)用

Promise原理與講解

原理
  • Promise的三種狀態(tài)
    • pending:進(jìn)行中
    • fulfilled :執(zhí)行成功
    • rejected :執(zhí)行失敗

    注意Promise在某一時(shí)刻只能處于一種狀態(tài)

  • Promise的狀態(tài)改變
    • pending------》fulfilled(resolved)
    • pending------》rejected

    Promise的狀態(tài)改變,狀態(tài)只能由pending轉(zhuǎn)換為rejected或者rejected,一旦狀態(tài)改變完成后將無法改變(不可逆性)

    用代碼講原理
  • 創(chuàng)建一個(gè)Promise
  • 創(chuàng)建Promise需要用到Promise的構(gòu)造函數(shù)來實(shí)現(xiàn),代碼如下:

    var promise=new Promise(function(resolve,reject){// ...some async code

    if(/* 一些異步操作成功*/) { resolve(value); }else { reject(error); }

    復(fù)制代碼

    }) 復(fù)制代碼

    代碼分析:

    • 在異步操作完成之后,會(huì)針對(duì)不同的返回結(jié)果調(diào)用resolve和reject。
    • resolve和reject是兩個(gè)函數(shù),resolve是異步操作成功時(shí)候被調(diào)用,將異步操作的返回值作為參數(shù)傳遞到外部;reject是異步操作出異常時(shí)候被調(diào)用,將錯(cuò)誤信息作為參數(shù)傳遞出去。
    • ==Promise其實(shí)沒有做任何實(shí)質(zhì)的代碼操作,它只是對(duì)異步操作回調(diào)函數(shù)的不同結(jié)果定義了不同狀態(tài)。==
    • resolve函數(shù)和reject函數(shù)只是把異步結(jié)果傳遞出去
  • 異步結(jié)果傳遞出去后,then來接 Promise對(duì)象將結(jié)果傳遞出來后,使用then方法來獲取異步操作的值: 代碼如下:
  • promise.then(function(value){//success

    },function(error){

    復(fù)制代碼

    }); 復(fù)制代碼

    代碼分析:

    • then方法將兩個(gè)匿名函數(shù)作為參數(shù),接收resolve和reject這兩個(gè)函數(shù)的值。
    • value是執(zhí)行成功的值,error是執(zhí)行出錯(cuò)時(shí)的錯(cuò)誤信息。
    • 對(duì)于error錯(cuò)誤異常結(jié)果出現(xiàn)的時(shí)候,可以不單獨(dú)寫匿名錯(cuò)誤的函數(shù),可以直接用catch拋出
    promise.then(function (data){//success }) .catch(function(error){//error }) 復(fù)制代碼
    • 注意then方法==只是==用來獲取異步操作的值。
  • then的返回值又是怎樣呢? 先看一段調(diào)用兩次then的代碼:
  • //之前創(chuàng)建promise操作后 promise.then(function(value){conlose.log(value); //有值 }.then(function(value) {conlose.log(value); //未定義 }); 復(fù)制代碼

    代碼分析:

    • 上面的第二個(gè)then方法中的值雖然是未定義,但是每一個(gè)then一定會(huì)==返回一個(gè)新的peomise對(duì)==象,但是默認(rèn)是一個(gè)空對(duì)象。
    • 對(duì)于這個(gè)空對(duì)象我們?nèi)绻肜^續(xù)做一些什么,需要進(jìn)行處理,可以用非空Promise對(duì)這個(gè)空的進(jìn)行賦值覆蓋,然后繼續(xù)then的鏈?zhǔn)秸{(diào)用。
    • then 中的==retuen==關(guān)鍵字很重要,聯(lián)系著下一個(gè)then的調(diào)用。
    幾個(gè)常用api
    • Promise.resolve resolve方法用來將一個(gè)非Promise對(duì)象轉(zhuǎn)化為Promise對(duì)象

    轉(zhuǎn)換的對(duì)象是一個(gè)常量或者不具備狀態(tài)的語句,轉(zhuǎn)換后的對(duì)象自動(dòng)處于resolve狀態(tài)。 轉(zhuǎn)換的后的結(jié)果和原來一樣

    var promise =Promise.resolve("hello world"); promise.then(function(result){console.log(result); //輸出結(jié)果 hello world }) 復(fù)制代碼

    轉(zhuǎn)換的對(duì)象如果直接是一個(gè)異步方法,不可以這么使用。

    • Promise.all(常用api) 多個(gè)promise需要執(zhí)行的時(shí)候,可以使用promise.all方法統(tǒng)一聲明,該方法可以將多個(gè)Promise對(duì)象包裝成一個(gè)Promise。

    代碼如下

    promise.all( //一系列promise操作 ).then(function(results){

    }).catch(function(error){

    復(fù)制代碼

    }); 復(fù)制代碼

    代碼分析:

    • promise.all對(duì)多有執(zhí)行結(jié)果做一個(gè)包裝傳給了then
    • promise.all中的執(zhí)行順序是怎么樣的,Promise的執(zhí)行順序是從被創(chuàng)建開始的,也就是在調(diào)用all的時(shí)候,==所有的promise都已經(jīng)開始執(zhí)行==了,all方法只是等到==所有的對(duì)象都執(zhí)行完成==,才會(huì)吧結(jié)果==傳遞給then==。
    • all中的promise,如果有一個(gè)狀態(tài)變成了reject那么轉(zhuǎn)換后的Promise字節(jié)變成reject,錯(cuò)誤信息傳遞哥catch,不會(huì)傳遞給then。(但是并不是說all這里面剛開始執(zhí)行成功的操作就不算數(shù)了)

    Promise在開發(fā)中的應(yīng)用

    項(xiàng)目開發(fā)中promise的應(yīng)用代碼:

    Promise.all([self.count({phoneNumber: mobile, createdOn: {$gt: hour}}),self.count({ip: ip, createdOn: {$gt: hour}})]).then(function (results) {if (results[0] >= 5) {return callback({code: -1, message: '短信發(fā)送頻率過快,每手機(jī)號(hào)1小時(shí)內(nèi)只能發(fā)送5次'});}if (results[1] >= 5) {return callback({code: -1, message: '短信發(fā)送頻率過快,每IP1小時(shí)內(nèi)只能發(fā)送5次'});}let code = {phoneNumber: mobile,code: tool.makeRandomStr(4, 1).toLowerCase(),createdOn: new Date(),expiredOn: new Date(new Date().getTime() + (20 * 60 * 1000)), //20分鐘失效ip: ip,isUsed: false};self.create(code, function (err, newCode) {if (newCode) {sms.sendSMS(mobile, newCode.code, 'ali', function (err, body) {console.log(body);if (err)console.log("短信驗(yàn)證碼發(fā)送失敗:", err);});callback({code: 0, message: "驗(yàn)證碼已經(jīng)發(fā)送"});} else {callback({code: -1, message: "驗(yàn)證碼發(fā)送失敗,請(qǐng)重試"});}})}) 復(fù)制代碼

    項(xiàng)目開發(fā)過程中使用promise.all的代碼,當(dāng)時(shí)是為了實(shí)現(xiàn)短信驗(yàn)證碼發(fā)送前的校驗(yàn)功能。 all中的兩個(gè)promise,第一個(gè)是統(tǒng)計(jì)時(shí)間內(nèi)該手機(jī)號(hào)發(fā)送驗(yàn)證碼數(shù)量;第二個(gè)是統(tǒng)計(jì)時(shí)間內(nèi)該ip發(fā)送驗(yàn)證碼的數(shù)量。

    Promise使用過程中注意事項(xiàng)與誤區(qū)

    注意事項(xiàng)在上面原理講解過程中,基本都提到過,只是重要的事情多說兩遍。

    • 狀態(tài)不可逆性
    • resolve函數(shù)和reject函數(shù)只是傳遞異步結(jié)果
    • then進(jìn)行層級(jí)調(diào)用的時(shí)候,每次的返回值都一個(gè)空promise對(duì)象,如果想繼續(xù)使用,賦值替換掉空promise對(duì)象,但是返回的時(shí)候return關(guān)鍵字很重要,不要忘了。
    • promise.all中的執(zhí)行順序是并行的,但是會(huì)等全部完成的結(jié)果傳遞給then
    • ==執(zhí)行順序==,promise是then方法調(diào)用之后才會(huì)執(zhí)行嗎?還是從創(chuàng)建那一刻就開始執(zhí)行? promise從創(chuàng)建那一刻就開始執(zhí)行,只是把結(jié)果傳遞給了then,then與promise的執(zhí)行無關(guān)。

    Promise的反思

    Promise的講解就到這里,但是大家在開發(fā)過程中,會(huì)發(fā)現(xiàn)有些時(shí)候多次操作異步會(huì)出現(xiàn)很多層級(jí)的調(diào)用,也就是

    promise.then(...)

    .then(...)

    復(fù)制代碼

    .then(...) 復(fù)制代碼

    這種情況,代碼雖然看起來會(huì)比callback的回調(diào)簡(jiǎn)介和規(guī)范了很多,但是還是感覺一些復(fù)雜,有沒有更好的解決辦法呢?請(qǐng)看下一篇博客

    回調(diào)的終極使用--async和await的講解

    覺得本文對(duì)你有幫助?請(qǐng)分享給更多人 我的公眾號(hào).jpg

    歡迎大家關(guān)注我的公眾號(hào)——程序員成長(zhǎng)指北。請(qǐng)自行微信搜索——“程序員成長(zhǎng)指北”

    總結(jié)

    以上是生活随笔為你收集整理的回调地狱解决方案之Promise的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。