用淺顯方式說明 Javascript 的 Promise

使用香草 js,製作一個簡單的 tab

前言:

最近在研究串接資料,剛好學習到了一個ES6的新用法,先來記錄說明一下。

在此之前我們還要了解什麼是同步與非同步

同步(synchronous):發一個請求,就要等待服務器的響應結束,然後才能發第二請求!中間這段時間就是 londing ;刷新的是整個頁面。

異步(asynchronous):發一個請求後,無需等待服務器的響應,然後就可以發第二個請求!可以使用 Javascript 接受服務器的響應,然後使用 Javascript 來局部刷新。

來個比較如下:

Async sync
one at a time more one at a time
執行了就馬上換下一個指令 第一個執行完才執行下一個

Async Actions

  • click, AJAX, SetInterval
  • 解決方法, callback , promises, async await (這一次不討論,因為他是promises 的簡寫)

先說說callback,就是在function裡面再執行一個function 這是目前傳統用法來解決同步非同步的事情。

var btn =document.querySelector('#btn');
var doIt = function() {
  alert("you triggered " + this.id);
};

btn.addEventListener("click", doIt);

我們可以說 doIt 就是一個 callback 函式,

回到今天想要講的 Promise :100:

  • ES6新語法
  • Promise 物件代表一個即將完成、或失敗的非同步操作, 以及它所產生的值。
  • return resolve or reject (用到了兩個參數)
  • ES6 Promise的實作中,會確保Promise物件一實體化後就會固定住狀態,要不就是"已實現",要不就是"已拒絕"

附註:resolve 和 reject 是參數 大概會是長像下面一樣:

const promise = new   Promise(function(resolve, reject) { 
    // 成功時 
    resolve(value) 
    // 失敗時 
    reject(reason) }); 

promise.then(function(value) { 
    // on fulfillment(已實現時) 
}, function(reason) { 
    // on rejection(已拒絕時) 
})
//http://eddychang.me/blog/javascript/88-promise-basic-usage.html

記住我們為什麼要把 Promise 用在 Ajax 上面:

Ajax 是屬於一個透過 JavaScript 技術名稱,用於取得遠端資料;而 Promise 則是一個語法,專門用來處理非同步行為,並不是專門用來處理 Ajax 使用,所以兩者是不同的。

中文翻譯意思:

如果想等 A 結束之後再進行 B..?

用一個生活化例子就是,我們去百貨公司美食街吃東西,點完餐店員會給你一個小圓盤,等那圓盤動了,就可以去拿吃的。 結果成功就是 resolve ,失敗了就是rejected

Promise:

如果成功的話… 如果失敗的話… (resolve)<–> (reject)

先備知識: 函式建構式要先了解比較好喔! JavaScript 建構式

new Promise 代表的是建立一個 Promise 物件,function(resolve, reject){} 代表的是建構式裡面包含的執行函式( executor function ),執行函式包含,resolve、reject,這兩個函式作為參數,當事件成功時便會回傳 resolve 裡面的值,反之當事件失敗便會回傳 reject 裡面的值。

接下來說個例子, 我們先設定攻擊的大絕招,成功之後(resolve) 會發生什麼事

let Bigtrick =  new Promise( (resolve,reject)=>{
  // 可能是⼀個需要花時間的動作..
  setTimeout(()=> resolve('火之呼吸'),3000);
  // setTimeout(function resolve(){
  //     resolve('火之呼吸');
  //   },3000)
  
});
Bigtrick
  .then((skill)=>console.log(`使用招式:${skill}`)) //promise成功
  .catch((err)=>console.log(`${err}無法使用`))//promise失敗

Bigtrick().then 的 then 代表了可以接收 Bigtrick() 這個 Promise 完成時,可以接受到回傳的值,如果回傳的值為錯誤時,則可以用 .catch 去做錯誤的值接收,.then 是可以一直串接下去的。這個行為叫做 Promise Chain

setTimeout()用法

MDN 定義 setTimeout() 的作用 是在延遲了某段時間 (單位為毫秒) 之後,才去執行「一次」指定的程式碼

接下來製作一個小遊戲, 範例網址 點擊一個按鈕連擊 5次以上在三秒之內,成功執行後會產生招式名稱。

我們先找到 按鈕和印出畫面的 dom,然後做出點擊時會發生的事件:數字chi變數=點擊次數出現在畫面

let chi =0;
let i =0;
let hitButton =document.getElementById('hitButton');
let result =document.getElementById('result');

hitButton.onclick=function(e){
  e.preventDefault();
  chi +=1;
  hitButton.innerHTML =`集氣 ${chi}次 `;
   
}

那我們利用 new Promise()實作,要在三秒以內,點擊數超過5次才會出現 水之呼吸(利用 setTimeout 方法)

  let bigSkill =new Promise((resolve,reject)=>{
    setTimeout(()=>{

      if(chi>=5){
      resolve('水之呼吸!!');
      }else{
      reject('水之呼吸!!');
      
      };
 
   },3000);
 });

成功達成條件後(點擊超過五次)resolve 就連上.then, 失敗 reject 就是被 catch 接到

 bigSkill
     .then( skill => result.innerHTML =`發動招式:${skill}`)
     .catch( err => result.innerHTML =`${err} 無法使用`)

畫面如下: image

其實 promise 不是必要,在以前沒有 promise 的時候也是可以做到非同步的事。在 promise 之前,可以用 callback 的方式來處理,但如果連續的處理的事情多,callback 就容易一層包一層,程式碼會變得不容易閱讀,俗稱「callback hell」

這樣是我真的對 callback function 怕怕的原因,函式包函式 ,腦袋都要昏了。

而 promise 的出現,可以簡化 callback 的流程,用 then .. then .. 的方式來解決 callback hell 的狀況喔。

資料來源:

五倍速紅寶石 使用 Promise 處理非同步 Promise 對象


comments powered by Disqus