普羅米修斯 Promise

盜火的普羅米修斯

  曾經我在哪本書上看過這樣的介紹,Promise 的英文是從希臘語的直譯Prometheus演變過來,Promise也就是表明着先知 將來的意思。在希臘神話中,是最具智慧的神明之一,最先的泰坦巨神後代,名字有「先見之明」(Forethought)的意思。泰坦十二神伊阿佩託斯與名望女神克呂墨涅的兒子。普羅米修斯不只創造了人類,給人類盜來了火,還教會了他們許多知識和技能。 後來因爲給人類帶來了火種,他吩咐火神給普羅米修斯最嚴厲的懲罰。天天還要派一直鷹去啄他的肝臟,夜晚的時候肝臟又會從新長出來,夜以繼日的承受折磨。


故事結束,開始吹牛X

異步函數 Promise

  我我的以爲Promise 函數跟 普羅米修斯很像,都是表明着處理將來的事情的先知。既然能處理將來的事情,那就表明着它擁有很是的能力,聽我慢慢吹來呀~ 首先來看看官方的吹牛文檔解釋:ajax

所謂Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果。從語法上說,Promise 是一個對象,從它能夠獲取異步操做的消息。Promise 提供統一的 API,各類異步操做均可以用一樣的方法進行處理。json

你看沒錯吧,是否是很像一個先知能夠處理將來的事情?既然是神仙確定是我們凡人管不了的,爲啥管不了那?就體如今它三個內部狀態上:api

對象的狀態不受外界影響。Promise對象表明一個異步操做,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)只有異步操做的結果,能夠決定當前是哪種狀態,任何其餘操做都沒法改變這個狀態。這也是Promise這個名字的由來,它的英語意思就是「承諾」,表示其餘手段沒法改變。數組

看見了嗎,敲黑板劃重點,神仙已經決定的東西就不能改變。並且一旦new Promise對象就不能取消,講究~promise

那如何使用那?下面來看一個簡單的例子:bash

const promise = new Promise (function(resolve, reject) { //這是先知啊,先知
  if (/* 異步操做成功 */){
    resolve(value);  // resolve就是這事兒先知贊成了,你就幹就完了
  } else {
    reject(error);  // reject就是這事兒先知不一樣意,白b扯了
  }
});
複製代碼

注意上面的事情其實有沒有發生?沒有,先知嘛預知將來的事情,何時發生那?固然先知贊成的時候也就是說狀態變成resolved。只要一resolved 立刻就能夠then了,劃重點 敲黑板 then 就是這玩意。app

promise.then(function(value) {
  // 妥妥的這個已經辦了,下面你想咋地吧?能夠連式操做無限then下去
}, function(error) {
  // 失敗了消停的把錯誤信息打出來把
  console.log("錯誤信息:"+error)
});
複製代碼

那麼坑人的玩意來了,請看下面代碼,誰先打印?異步

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');
複製代碼

上面代碼中,Promise 新建後當即執行,因此首先輸出的是Promise。而後,then方法指定的回調函數,將在當前腳本全部同步任務執行完纔會執行,因此resolved最後輸出。那麼接下來這段 函數

你要是能直接寫出答案,基本Promise就不用看了,根據上面的理論,Promise一旦創建立刻就執行,可是我們說了 resolve 是將來的狀態,因此第二行代碼先等一等,三行代碼也不用看了,確定是四行代碼先執行,而後往下走 第六行執行,回過頭來 第三行直接成功了,因此會接下去執行,最後一個不用我說了吧,第二行代碼須要走個完成的resolve狀態,把1傳遞給第五行的t參數,因此確定是最後執行的。


概念吹完了,來看勢力post

妥了,接下來看一個用Promise對象實現的 Ajax 操做的實例:

const getJSON = function(url) { 
  const promise = new Promise(function(resolve, reject){
    const handler = function() {
      if (this.readyState !== 4) {
        return;
      }
      if (this.status === 200) {
        resolve(this.response);
      } else {
        reject(new Error(this.statusText));
      }
    };
    const client = new XMLHttpRequest();
    client.open("GET", url);
    client.onreadystatechange = handler;
    client.responseType = "json";
    client.setRequestHeader("Accept", "application/json");
    client.send();

  });

  return promise;
};

getJSON("/posts.json").then(function(json) {
  console.log('Contents: ' + json);
}, function(error) {
  console.error('出錯了', error);
});
複製代碼

是否是很簡單,一點都不難,只是把ajax的操做流程放到了先知的內部,讓先知幫你獲取各類成功失敗的狀態!結合實際,咱們在工做中可能一次要請求好幾個接口的數據,Promise提供了一個更加簡單的方法

const p = Promise.all([p1, p2, p3]);
複製代碼

很好理解,all 的參數表明這一個可執行的任務隊列,只要裏面有任務就能夠往下執行,也就是我們訪問的多個api集合組成的數組。

// 生成一個Promise對象的數組
const promises = [2, 3, 5, 7, 11, 13].map(function (id) {
  return getJSON('/post/' + id + ".json"); //ID 做爲參數 變成動態請求
});

Promise.all(promises).then(function (posts) {
  // ...
}).catch(function(reason){
  // ...
});
複製代碼

還有一個相似 all的api Promise.race,Promise.race方法的參數與Promise.all方法同樣,若是不是 Promise 實例,就會先調用下面講到的Promise.resolve方法,將參數轉爲 Promise 實例,再進一步處理

const p = Promise.race([
  fetch('/resource-that-may-take-a-while'),
  new Promise(function (resolve, reject) {
    setTimeout(() => reject(new Error('request timeout')), 5000)
  })
]);

p
.then(console.log)
.catch(console.error);
複製代碼

上面代碼中,若是 5 秒以內fetch方法沒法返回結果,變量p的狀態就會變爲rejected,從而觸發catch方法指定的回調函數。

妥妥滴,既然到這裏我估計你應該懂了,其實任何技術都不難,都能拆分紅若干個簡單點。任意簡單的點組合起來就又複雜了,正所謂大道至簡,相信萬事萬物都是簡單的原理,懷着敬畏的心理去學習,終究會獲得本身的收穫。

相關文章
相關標籤/搜索