一個使用javascript promise的例子

來源:互聯網
上載者:User
複雜的非同步代碼變得簡單了

OK,現在我們來寫點實際的代碼。假設我們想要: 顯示一個載入指示表徵圖 載入一篇小說的 JSON,包含小說名和每一章內容的 URL。 在頁面中填上小說名 載入所有章節本文 在頁面中添加章節本文 停止載入指示

……這個過程中如果發生什麼錯誤了要通知使用者,並且把載入指示停掉,不然它就會不停轉下去,令人眼暈,或者搞壞介面什麼的。

當然了,你不會用 JavaScript 去這麼繁瑣地顯示一篇文章,直接輸出 HTML 要快得多,不過這個流程是非常典型的 API 請求模式:擷取多個資料,當它們全部完成之後再做一些事情。

首先,搞定從網路載入資料的步驟: 將 Promise 用於 XMLHttpRequest

只要能保持向後相容,現有 API 都會更新以支援 Promise,XMLHttpRequest 是重點考慮對象之一。不過現在我們先來寫個 GET 請求:

function get(url) {  // 返回一個新的 Promise  return new Promise(function(resolve, reject) {    // 經典 XHR 操作    var req = new XMLHttpRequest();    req.open('GET', url);    req.onload = function() {      // 當發生 404 等狀況的時候調用此函數      // 所以先檢查狀態代碼      if (req.status == 200) {        // 以響應文本為結果,完成此 Promise        resolve(req.response);      }      else {        // 否則就以狀態代碼為結果否定掉此 Promise        // (提供一個有意義的 Error 對象)        reject(Error(req.statusText));      }    };    // 網路異常的處理方法    req.onerror = function() {      reject(Error("Network Error"));    };    // 發出請求    req.send();  });}

現在可以調用它了:

get('story.json').then(function(response) {  console.log("Success!", response);}, function(error) {  console.error("Failed!", error);});

點擊這裡查看代碼。現在我們不需要手敲 XMLHttpRequest 就可以直接發起 HTTP 要求,這樣感覺好多了,能少看一次這個狂駝峰命名的 XMLHttpRequest 我就多快樂一點。 鏈式調用

“then”的故事還沒完,你可以把這些“then”串聯起來修改結果或者添加進行更多非同步作業。 值的處理

你可以對結果做些修改然後返回一個新值:

var promise = new Promise(function(resolve, reject) {  resolve(1);});promise.then(function(val) {  console.log(val); // 1  return val + 2;}).then(function(val) {  console.log(val); // 3});

回到前面的代碼:

get('story.json').then(function(response) {  console.log("Success!", response);});

收到的響應是一個純文字的 JSON,我們可以修改 get 函數,設定 responseType為 JSON 來指定伺服器響應格式,也可以在 Promise 的世界裡搞定這個問題:

get('story.json').then(function(response) {  return JSON.parse(response);}).then(function(response) {  console.log("Yey JSON!", response);});

既然 JSON.parse 只接收一個參數,並返迴轉換後的結果,我們還可以再精簡一下:

get('story.json').then(JSON.parse).then(function(response) {  console.log("Yey JSON!", response);});

點擊這裡查看代碼運行頁面,開啟控制台查看輸出結果。 事實上,我們可以把getJSON 函數寫得超級簡單:

function getJSON(url) {  return get(url).then(JSON.parse);}

getJSON 會返回一個擷取 JSON 並加以解析的 Promise。 隊列的非同步作業

你也可以把“then”串聯起來依次執行非同步作業。

當你從“then”的回呼函數返回的時候,這裡有點小魔法。如果你返回一個值,它就會被傳給下一個“then”的回調;而如果你返回一個“類 Promise”的對象,則下一個“then”就會等待這個 Promise 明確結束(成功/失敗)才會執行。例如:

getJSON('story.json').then(function(story) {  return getJSON(story.chapterUrls[0]);}).then(function(chapter1) {  console.log("Got chapter 1!", chapter1);});

這裡我們發起一個對“story.json”的非同步請求,返回給我們更多 URL,然後我們會請求其中的第一個。Promise 開始首次顯現出相較事件回調的優越性了。你甚至可以寫一個抓取章節內容的獨立函數:

var storyPromise;function getChapter(i) {  storyPromise = storyPromise || getJSON('story.json');    return storyPromise.then(function(story) {    return getJSON(story.chapterUrls[i]);  })}// 用起來非常簡單:getChapter(0).then(function(chapter) {  console.log(chapter);  return getChapter(1);}).then(function(chapter) {  console.log(chapter);});

我們一開始並不載入 story.json,直到第一次 getChapter,而以後每次getChapter 的時候都可以重用已經載入完成的 story Promise,所以 story.json 只需要請求一次。Promise 好棒。 錯誤處理

前面已經看到,“then”接受兩個參數,一個處理成功,一個處理失敗(或者說肯定和否定,按 Promise 術語):

get('story.json').then(function(response) {  console.log("Success!", response);}, function(error) {  console.log("Failed!", error);});

你還可以使用“catch”:

get('story.json').then(function(response) {  console.log("Success!", response);}).catch(function(error) {  console.log("Failed!", error);});

這裡的 catch 並無任何特殊之處,只是 then(undefined, func) 的文法糖衣,更直觀一點而已。注意上面兩段代碼的行為不僅相同,後者相當於:

get('story.json').then(function(response) {  console.log("Success!", response);}).then(undefined, function(error) {  console.log("Failed!", error);});

差異不大,但意義非凡。Promise 被否定之後會跳轉到之後第一個配置了否定回調的 then(或 catch,一樣的)。對於 then(func1, func2) 來說,必會調用 func1或 func2 之一,但絕不會兩個都調用。而 then(func1).catch(func2) 這樣,如果 func1 返回否定的話 func2 也會被調用,因為他們是鏈式調用中獨立的兩個步驟。看下面這段代碼:

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.