1. 程式人生 > >Promise,Ajax,fetch

Promise,Ajax,fetch

一、Promise相關

new Promise(
    /* executor:executor是一個帶有resolve和reject兩個引數的函式 。 */
    function(resolve, reject) {...}
);
resolve 函式被呼叫時將promise的狀態改為fulfilled(完成)
reject 函式被呼叫時將promise的狀態改為rejected(失敗)。

一個 Promise有以下三種狀態:
pending: 初始狀態,不是成功或失敗狀態。
fulfilled: 意味著操作成功完成。
rejected: 意味著操作失敗。


pending 狀態的 Promise 物件某個 狀態並傳遞一個值給相應的狀態處理方法時,Promise 物件的 then 方法繫結的處理方法(handlers )就會被呼叫(then方法包含兩個引數:onfulfilled 和 onrejected,它們都是 Function 型別。當Promise狀態為fulfilled時,呼叫 then 的 onfulfilled 方法,當Promise狀態為rejected時,呼叫 then 的 onrejected 方法, 所以在非同步操作的完成和繫結處理方法之間不存在競爭)。


Promise.all(iterable)
iterable引數物件裡所有的promise物件都成功的時候才會觸發成功,有一個失敗則立即觸發該promise物件的失敗。這個新的promise物件在觸發成功狀態以後,會把一個包含iterable裡所有promise返回值的陣列作為成功回撥的返回值,順序跟iterable的順序保持一致;如果這個新的promise物件觸發了失敗狀態,它會把iterable裡第一個觸發失敗的promise物件的錯誤資訊作為它的失敗錯誤資訊。Promise.all方法常被用於處理多個promise物件的狀態集合。
Promise.race(iterable)
當iterable引數裡的任意一個子promise被成功或失敗後,父promise馬上也會用子promise的成功返回值或失敗詳情作為引數呼叫父promise繫結的相應控制代碼,並返回該promise物件。
Promise.reject(reason)
返回一個狀態為失敗的Promise物件,並將給定的失敗資訊傳遞給對應的處理方法
Promise.resolve(value)
返回一個狀態由給定value決定的Promise物件。如果該值是一個Promise物件,則直接返回該物件;如果該值是thenable(即,帶有then方法的物件),返回的Promise物件的最終狀態由then方法執行決定;否則的話(該value為空,基本型別或者不帶then方法的物件),返回的Promise物件狀態為fulfilled,並且將該value傳遞給對應的then方法。通常而言,如果你不知道一個值是否是Promise物件,使用Promise.resolve(value) 來返回一個Promise物件,這樣就能將該value以Promise物件形式使用。

栗子:

var myFirstPromise = new Promise(function(resolve, reject){
    //當非同步程式碼執行成功時,我們才會呼叫resolve(...), 當非同步程式碼失敗時就會呼叫reject(...)
    //在本例中,我們使用setTimeout(...)來模擬非同步程式碼,實際編碼時可能是XHR請求或是HTML5的一些API方法.
    setTimeout(function(){
        resolve("成功!"); //程式碼正常執行!
    }, 250);
});

myFirstPromise.then(function(successMessage){
    //successMessage的值是上面呼叫resolve(...)方法傳入的值.
    //successMessage引數不一定非要是字串型別,這裡只是舉個例子
    console.log("Yay! " + successMessage);
});
二、Fetch

https://developer.mozilla.org/zh-CN/docs/Web/API/GlobalFetch/fetch
fetch() 方法用於發起獲取資源的請求。它返回一個 promise,這個 promise 會在請求響應後被 resolve,並傳回 Response 物件。
當遇到網路錯誤時,fetch() 返回的 promise 會被 reject,並傳回 TypeError,雖然這也可能因為許可權或其它問題導致。成功的 fetch() 檢查不僅要包括 promise 被 resolve,還要包括 Response.ok 屬性為 true。HTTP 404 狀態並不被認為是網路錯誤。


Promise<Response> fetch(input[, init]);
input可能是個 USVString 字串,包含要獲取資源的 URL;也有可能是個Request物件
FetchAPI的Request 介面用來表示資源請求。
屬性:
Request.method:請求使用的方法 (GET, POST, 等.)
Request.url:請求使用的 URL。
Request.headers:請求所關聯的 Headers 物件。

方法:
Request.clone():建立當前request的副本。

返回值
一個 Promise,resolve 時回傳 Response 物件。

var myImage = document.querySelector('img');//HTML5新增方法
var myRequest = new Request('flowers.jpg');//var myRequest = new Request('flowers.jpg',myInit);
fetch(myRequest).then(function(response) {
  return response.blob();
}).then(function(response) {
  var objectURL = URL.createObjectURL(response);
  myImage.src = objectURL;
});

var myImage = document.querySelector('img');
var myHeaders = new Headers();
myHeaders.append('Content-Type', 'image/jpeg');
var myInit = { method: 'GET',
               headers: myHeaders,
               mode: 'cors',
               cache: 'default' };
var myRequest = new Request('flowers.jpg');
fetch(myRequest,myInit).then(function(response) {
  ... 
});

Fetch 優點主要有:
語法簡潔,更加語義化
基於標準 Promise 實現,支援 async/await
同構方便,使用 isomorphic-fetch
Fetch 常見坑
Fetch 請求預設是不帶 cookie 的,需要設定 fetch(url, {credentials: 'include'})
伺服器返回 400,500 錯誤碼時並不會 reject,只有網路錯誤這些導致請求不能完成時,fetch 才會被 reject。
IE 使用策略
所有版本的 IE 均不支援原生 Fetch,fetch-ie8 會自動使用 XHR 做 polyfill。但在跨域時有個問題需要處理。
IE8, 9 的 XHR 不支援 CORS 跨域,雖然提供 XDomainRequest,但這個東西就是玩具,不支援傳 Cookie!如果介面需要許可權驗證,還是乖乖地使用 jsonp 吧。

三、Ajax和fetch比較

fetch被稱為下一代ajax技術,與 Ajax 不同的是,它的 API 不是事件機制,而採用了 Promise 方式處理,目前還不是 W3C 規範

Ajax的本質是使用XMLHttpRequest物件來請求資料
fetch 是全域性量 window 的一個方法,它的主要特點有:
1、第一個引數是URL:
2、第二個是可選引數,可以控制不同配置的 init 物件
3、使用了 JavaScript Promises 來處理結果/回撥:

區別:
1、從 fetch()返回的 Promise 將不會拒絕HTTP錯誤狀態, 即使響應是一個 HTTP 404 或 500。相反,它會正常解決 (其中ok狀態設定為false), 並且僅在網路故障時或任何阻止請求完成時,它才會拒絕。
2、預設情況下, fetch在服務端不會發送或接收任何 cookies, 如果站點依賴於維護一個使用者會話,則導致未經認證的請求(要傳送 cookies,必須傳送憑據頭).
如果想要在同域中自動傳送cookie,加上 credentials 的 same-origin 選項

fetch(url, {
  credentials: ’same-origin'
})
same-origin值使得fetch處理Cookie與XMLHttpRequest類似。 否則,Cookie將不會被髮送,導致這些請求不保留認證會話。
對於CORS請求,使用include值允許將憑據傳送到其他域:
fetch(url, {
  credentials: 'include'
})

四、async/await

ES7的Async/Await?

栗子:

這裡我們要實現一個暫停功能,輸入N毫秒,則停頓N毫秒後才繼續往下執行。

var sleep = function (time) {
    return new Promise(function (resolve, reject) {
        setTimeout(function () {
            resolve();
        }, time);
    })
};

var start = async function () {
    try {
	// 在這裡使用起來就像同步程式碼那樣直觀
        console.log('start');
        await sleep(3000); // 這裡得到了一個返回錯誤
        
        // 所以以下程式碼不會被執行了
        console.log('end');
    } catch (err) {
        console.log(err); // 這裡捕捉到錯誤 `error`
    }
};

start();

轉自:https://segmentfault.com/a/1190000007535316
async 表示這是一個async函式,await只能用在這個函式裡面。await 表示在這裡等待promise返回結果了,再繼續執行。await 後面跟著的應該是一個promise物件(當然,其他返回值也沒關係,只是會立即執行,不過那樣就沒有意義了…)
async 用於申明一個 function 是非同步的,而 await 用於等待一個非同步方法執行完成。
一般來說,都認為 await 是在等待一個 async 函式完成。不過按語法說明,await 等待的是一個表示式,這個表示式的計算結果是 Promise 物件或者其它值(換句話說,就是沒有特殊限定)。因為 async 函式返回一個 Promise 物件,所以 await 可以用於等待一個 async 函式的返回值——這也可以說是 await 在等 async 函式,但要清楚,它等的實際是一個返回值。注意到 await 不僅僅用於等 Promise 物件,它可以等任意表達式的結果await 等到了它要等的東西,一個 Promise 物件,或者其它值,然後呢?我不得不先說,await 是個運算子,用於組成表示式,await 表示式的運算結果取決於它等的東西。       如果它等到的不是一個 Promise 物件,那 await 表示式的運算結果就是它等到的東西。       如果它等到的是一個 Promise 物件,await 就忙起來了,它會阻塞後面的程式碼,等著 Promise 物件 resolve,然後得到 resolve 的值,作為 await 表示式的運算結果。async/await 的優勢在於處理 then 鏈單一的 Promise 鏈並不能發現 async/await 的優勢,但是,如果需要處理由多個 Promise 組成的 then 鏈的時候,優勢就能體現出來了(很有意思,Promise 通過 then 鏈來解決多層回撥的問題,現在又用 async/await 來進一步優化它)。
栗子:
假設一個業務,分多個步驟完成,每個步驟都是非同步的,而且依賴於上一個步驟的結果。我們仍然用 setTimeout 來模擬非同步操作:

function doIt() {
    console.time("doIt");
    const time1 = 300;
    step1(time1)
        .then(time2 => step2(time2))
        .then(time3 => step3(time3))
        .then(result => {
            console.log(`result is ${result}`);
            console.timeEnd("doIt");
        });
}
doIt();
// c:\var\test>node --harmony_async_await .
// step1 with 300
// step2 with 500
// step3 with 700
// result is 900
// doIt: 1507.251ms

async function doIt() {
    console.time("doIt");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time2);
    const result = await step3(time3);
    console.log(`result is ${result}`);
    console.timeEnd("doIt");
}




doIt();


厲害了