Magren

Magren

Idealist & Garbage maker 🛸
twitter
jike

es6中的承諾

Promise,簡單說就是一個容器,裡面保存著某個未來才會結束的事件(通常是一個異步操作)的結果。從語法上說,Promise 是一個對象,從它可以獲取異步操作的消息。

有了 Promise 對象,就可以將異步操作以同步操作的流程表達出來,避免了層層嵌套的回調函數。此外,Promise 對象提供統一的接口,使得控制異步操作更加容易。

Promise 也有一些缺點:

  1. 首先,無法取消 Promise,一旦新建它就會立即執行,無法中途取消。
  2. 如果不設置回調函數,Promise 內部拋出的錯誤,不會反應到外部。
  3. 當處於 pending 狀態時,無法得知目前進展到哪一個階段(剛剛開始還是即將完成)。

promise 的特點#

  1. 對象的狀態不受外界影響。Promise 對象代表一個異步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和 rejected(已失敗)。
  2. 一旦狀態改變,就不會再變,任何時候都可以得到這個結果。Promise 的對象狀態改變,要麼是成功,要麼就是失敗,只要發生這兩種情況,狀態就會凝固,稱為 resolved(已定型)。改變發生後,再添加回調函數,也是會得到這個結果。

用法#

創造 Promise 實例#

Promise 對象是一個構造函數,用來生成 Promise 實例。

const promise = new Promise(function(resolve, reject) {
  if (/* 異步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

resolve 函數的作用是,將 Promise 對象的狀態從 “未完成” 變為 “成功”(即從 pending 變為 resolved),在異步操作成功時調用,並將異步操作的結果,作為參數傳遞出去;

reject 函數的作用是,將 Promise 對象的狀態從 “未完成” 變為 “失敗”(即從 pending 變為 rejected),在異步操作失敗時調用,並將異步操作報出的錯誤,作為參數傳遞出去。

then 方法#

接著用then方法指定 resolved 狀態和 rejected 狀態的回調函數:

promise.then(function(value) {
  // success
}, function(error) {
  // failure
});

第一個函數是狀態對象變為 rejected 的調用,第二個是 resolved 的調用,第二個函數是可選的。

then 方法返回的是一個新的 Promise 實例(注意,不是原來那個 Promise 實例)。因此可以採用鏈式寫法,即 then 方法後面再調用另一個 then 方法。

promise.then(function(value) {
  
}.then(function (comments) {
  console.log("resolved: ", comments);
}, function (err){
  console.log("rejected: ", err);
});

catch 方法#

用於指定發生錯誤時的回調函數。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
}).catch(function(error) {
  // 處理發生的錯誤
  console.log('發生錯誤!', error);
});

如果異步操作拋出錯誤,狀態就會變為 rejected,就會調用 catch () 方法指定的回調函數,處理這個錯誤。另外,then () 方法指定的回調函數,如果運行中拋出錯誤,也會被 catch () 方法捕獲。

跟傳統的 try/catch 代碼塊不同的是,如果沒有使用 catch () 方法指定錯誤處理的回調函數,Promise 對象拋出的錯誤不會傳遞到外層代碼,即不會有任何反應。

finally 方法#

用於指定不管 Promise 對象最後狀態如何,都会執行的操作。

promise.then(function(value) {
  // success
}, function(error) {
  // failure
}).catch(function(error) {
  // 處理發生的錯誤
  console.log('發生錯誤!', error);
}).finally(function(){
    alert("finish");
});

finally 方法的回調函數不接受任何參數, 意味著無法知道最終的狀態是怎樣的。

Jquery、Ajax、Promise 示例#

之前學了 Jquery 和 ajax,就順手在網上隨便找了個 api 測試下:

const apiUrl = "https://suggest.taobao.com/sug?code=utf-8&q=電腦&callback=cb";
$("##bt").click(apiUrl,function(event){
     const promise = new Promise(function(resolve,reject){
       $.ajax({
           url: event.data,
           type:"get",
           dataType:"jsonp",
           headers: {      
                       Accept: "application/json; charset=utf-8",
                   },
           success: function(data) {
            resolve(data);   
           },
           error: function(XMLHttpRequest, textStatus, errorThrown) {
               reject(XMLHttpRequest,textStatus,errorThrown)
           },
       })
   })

   promise.then(function(data){
       console.log(data);
       let x = data.result;
       for(let i = 0 ; i<data.result.length;i++){
           console.log(x[i][0]);
       }
   },function(XMLHttpRequest, textStatus, errorThrown){
       alert(XMLHttpRequest);
       alert(textStatus);
       alert(errorThrown);
   }).catch(function(error){
       console.log(error);
   }).finally(function(){
       alert("finish");
   });
});

結果:

遇到的問題#

其實在 Promise 基礎的學習上沒有什麼太大的問題,但是在 ajax 請求的時候遇上了一個跨域的問題,就是:

Access to XMLHttpRequest at ‘這裡是 api’ from origin ‘null’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

這是什麼啊……
簡單的了解了下,先說說跨域的概念吧

每個網站只能讀取同一來源的數據,這裡的同一來源指的是主機名 (域名)、協議 (http/https) 和端口號的組合。在沒明確授權的情況下,不能讀寫對方的資源,它是瀏覽器最核心也最基本的安全功能;只要有一個不一樣就跨域。

而 Ajax 的 XMLHttpRequest 受到了同源限制,只能訪問同源下的數據,所以就報這個錯。
所以怎麼還沒說怎麼解決嗷???

在搜到的文章裡面大部分都是後端配合設置一個請求權限,但是我這是野生的 api。。。我還腆著臉去要求別人做這做那哦?

直到我找到個方法,jsonp

jsonp:

  • 通過 script 標籤引入某些數據,是同步模式的,用 script 標籤做跨域的時候,不建議將數據提前加載,需要按需加載;
  • 當需要數據的時候創建一個 script 標籤,將需要的數據放在 src 中,通過 onload 去監聽是否請求過來,請求完畢就調用傳回來的數據(異步加載);
  • jsonp 不能用 post 請求,只能是 get 請求;

所以為啥這個類型就可以跨域了???

帶 src 屬性 script、img、iframe、link 等標籤是不需要遵守同源策略的,但是通過 src 加載的資源,瀏覽器限制了 javascript 的權限,能讀不能寫

綜上所述:把 dataType 類型從 json 改成 jsonp 就可以了。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。