JS promise用法總結(jié)

0、前言

????????處在前后端分離開發(fā)模式的時代抄淑,前端向后端請求數(shù)據(jù)似乎已經(jīng)司空見慣觉至,在稍微復(fù)雜一點的業(yè)務(wù)中就可能遇到串行接口的情況,這就會產(chǎn)生回調(diào)嵌套助赞,回調(diào)過深會導(dǎo)致代碼可維護性差,因此需要一種解決回調(diào)過深的方案:promise赐劣。ES6 promise語法精深嫉拐,本文只介紹工作中最常用到的promise相關(guān)知識。

1魁兼、promise語法

  • 創(chuàng)建promise
var promise = new Promise(function(resolve, reject) {
  // ... some code
  if (/* 異步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});
//實例
function loadImageAsync(url) {
  return new Promise(function(resolve, reject) {
    var image = new Image();

    image.onload = function() {
      resolve(image);
    };

    image.onerror = function() {
      reject(new Error('Could not load image at ' + url));
    };

    image.src = url;
  });
}

創(chuàng)建promise最重要的操作就是確定何時執(zhí)行resolve方法

  • Promise.prototype.then方法
  1. 雖然then方法接受兩個函數(shù)作為參數(shù),但一般只寫成功回調(diào),并用catch代替失敗回調(diào)
//bad
promise.then(successFn,errorFn)
//good
promise.then(successFn).catch(errorFn)
  1. 根據(jù)successFn返回的結(jié)果咐汞,then有不同的返回值,then方法總是返回一個新的promise:
    2.1 當successFn返回普通值v1時盖呼,then返回原來的promise,并將v1作為后續(xù)then方法的成功回調(diào)參數(shù)化撕;
    2.2 當successFn返回已經(jīng)被resolved的promise時几晤,then返回原來的promise,并將successFn返回的promise值作為后續(xù)then方法的成功回調(diào)參數(shù)植阴;
    2.3 當successFn返回一個未被resolved的promise1時蟹瘾,then方法返回的promise將與promise1具有一致的狀態(tài),可以看成then方法返回了promise1
  • Promise.prototype.resolve方法
    根據(jù)resolve方法接受的參數(shù)類型分為:
    1掠手、promise憾朴,直接返回這個promise
    2、普通類型(不包含then方法的對象)喷鸽,返回一個立即resolve的promise
    3众雷、不傳參數(shù),返回一個立即resolve的promise
  • Promise.prototype.all方法
    接受promise組成的數(shù)組做祝,并能使結(jié)果有序返回砾省。缺點是一旦其中一個promise被rejected,所有數(shù)據(jù)都拿不到了混槐。返回的結(jié)果以數(shù)組形式存儲编兄,可按下標依次取出

2、promise運用場景

1声登、單個請求promise化

//異步加載圖片
function loadImageAsync(url) {
  return new Promise(function(resolve, reject) {
    var image = new Image();
    image.onload = function() {
      resolve(image);
    };
    image.onerror = function() {
      reject(new Error('Could not load image at ' + url));
    };
    image.src = url;
  });
}
loadImageAsync(url).then(successFn).catch(handleError)

2翻诉、多個串行請求promise化
場景:先拿用戶信息,再獲取數(shù)據(jù)

//方案1
getUserInfo().then(getData).then(successFn).catch(handleError)
方案2
async function fn(){
    let userInfo=await getUserInfo();
    let data=await getData(userInfo);
    return data;
}
fn().then(successFn).catch(errorFn);

方案2的async函數(shù)寫法使得串行的鏈式調(diào)用變成了同步寫法捌刮,語義更加清楚
3碰煌、多個并行請求promise化
場景:一次性拿不同tab下的數(shù)據(jù)
方案1:使用Promise.all()方法

let tab1_promise=getHotData();
let tab2_promise=getLatestData();
let arr=[tab1_promsie,tab2_promise];
Promise.all(arr).then(([tab1_data,tab2_data])=>handleFn).catch(errorFn);

這種方式顯然有風險,可考慮如下方案2
方案2:順序執(zhí)行promise

let arr=[tab1_promise,tab2_promise];
arr.reduce((task,promise)=>{
      return task.then(()=>return promise).then(successFn);
},Promise.resolve());

這種方案可以對每個promise的返回值單獨處理绅作,不必等到所有數(shù)據(jù)一起返回才處理芦圾,更加靈活

3、總結(jié)

  • 創(chuàng)建一個promise的關(guān)鍵在于確定resolve的執(zhí)行時機
  • then方法總是返回一個新的promise
  • 使用這種寫法promise.then(successFn).catch(errorFn),而不是promise.then(successFn,errorFn)
  • Promise.reslove()可以創(chuàng)造一個立即resolve的promise俄认,結(jié)合reduce方法可使代碼更加精煉
  • async函數(shù)基于Promise个少,可解決串行鏈式調(diào)用過長的問題,并且語義清楚眯杏,推薦使用
  • Promise.all方法有風險夜焦,盡量不用

4、超時和可取消的Promise

// 可取消的Promise(本質(zhì)上并沒有取消請求岂贩,只是不用promise的返回值而已)
export default function makeCancelable(promise){
    let hasCanceled_ = false;
    const wrappedPromise = new Promise((resolve, reject) => {
        promise.then((val) =>
            hasCanceled_ ? reject({isCanceled: true}) : resolve(val)
        );
        promise.catch((error) =>
            hasCanceled_ ? reject({isCanceled: true}) : reject(error)
        );
    });
    return {
        promise: wrappedPromise,
        cancel() {
            hasCanceled_ = true;
        },
    };
}

// 超時的Promise
export const makeTimeoutPromise = ({ timeout = 300000, callback,promise }) => {
  // 默認5分鐘超時
  let hasTimeout = false;
  let timer = setTimeout(() => {
    hasTimeout = true;
  }, timeout);
  const wrappedPromise = new Promise((resolve, reject) => {
        promise.then((val) =>
            hasTimeout ? reject({hasTimeout: true}) : resolve(val)
        ).catch((error) =>
            hasTimeout ? reject({hasTimeout: true}) : reject(error)
        ).finally(()=>timer && clearTimeout(timer))
  }
  return wrappedPromise;
};

掌握以上這些茫经,應(yīng)該能夠應(yīng)對工作中JS的異步處理了
https://mp.weixin.qq.com/s/cN40pHBfttZ3O2oEbVPAcg

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子卸伞,更是在濱河造成了極大的恐慌抹镊,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荤傲,死亡現(xiàn)場離奇詭異垮耳,居然都是意外死亡,警方通過查閱死者的電腦和手機遂黍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進店門终佛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人雾家,你說我怎么就攤上這事铃彰。” “怎么了榜贴?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵豌研,是天一觀的道長。 經(jīng)常有香客問我唬党,道長鹃共,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任驶拱,我火速辦了婚禮霜浴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蓝纲。我一直安慰自己阴孟,他們只是感情好,可當我...
    茶點故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布税迷。 她就那樣靜靜地躺著永丝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪箭养。 梳的紋絲不亂的頭發(fā)上慕嚷,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天,我揣著相機與錄音毕泌,去河邊找鬼喝检。 笑死,一個胖子當著我的面吹牛撼泛,可吹牛的內(nèi)容都是我干的挠说。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼愿题,長吁一口氣:“原來是場噩夢啊……” “哼损俭!你這毒婦竟也來了蛙奖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤撩炊,失蹤者是張志新(化名)和其女友劉穎外永,沒想到半個月后崎脉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拧咳,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年囚灼,在試婚紗的時候發(fā)現(xiàn)自己被綠了骆膝。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,498評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡灶体,死狀恐怖阅签,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蝎抽,我是刑警寧澤政钟,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站樟结,受9級特大地震影響养交,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瓢宦,卻給世界環(huán)境...
    茶點故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一碎连、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧驮履,春花似錦鱼辙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至恐似,卻和暖如春杜跷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蹂喻。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工葱椭, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人口四。 一個月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓孵运,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蔓彩。 傳聞我的和親對象是個殘疾皇子治笨,可洞房花燭夜當晚...
    茶點故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 你不知道JS:異步 第三章:Promises 在第二章驳概,我們指出了采用回調(diào)來表達異步和管理并發(fā)時的兩種主要不足:缺...
    purple_force閱讀 2,071評論 0 4
  • 本文適用的讀者 本文寫給有一定Promise使用經(jīng)驗的人,如果你還沒有使用過Promise旷赖,這篇文章可能不適合你顺又,...
    HZ充電大喵閱讀 7,313評論 6 19
  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持,譯者再次奉上一點點福利:阿里云產(chǎn)品券等孵,享受所有官網(wǎng)優(yōu)惠稚照,并抽取幸運大...
    HetfieldJoe閱讀 11,028評論 26 95
  • 00果录、前言Promise 是異步編程的一種解決方案,比傳統(tǒng)的解決方案——回調(diào)函數(shù)和事件——更合理和更強大咐熙。它由社區(qū)...
    夜幕小草閱讀 2,134評論 0 12
  • 雖然Object構(gòu)造函數(shù)或?qū)ο笞置媪慷伎梢杂脕韯?chuàng)建單個對象弱恒,但這些方式有個明顯的缺點:使用同一個接口創(chuàng)建很多對象,...
    frankisbaby閱讀 186評論 0 0