JavaScript深入理解-Promise以及常用方法詳解


Promise

Promise 介紹

Promise 對象表示一個異步操作的最終完成(或失敗)及其結果值。

狀態:

一個 promise 必然處於以下幾種狀態之一

  • 待定:初始狀態(pending)
  • 已兌現:操作成功完成(fulfilled)
  • 已拒絕:操作失敗(reject)

創建 Promise

Promise 對象是由關鍵字 new 及其構造函數來創建的。該構造函數會把一個叫做“處理器函數”(executor function)的函數作為它的參數。這個“處理器函數”接受兩個函數——resolve 和 reject ——作為其參數。當異步任務順利完成且返回結果值時,會調用 resolve 函數;而當異步任務失敗且返回失敗原因(通常是一個錯誤對象)時,會調用 reject 函數。

new Promise((resolve, reject) => {
  //處理操作  返回resolve或者reject
  if (flag) resolve(data);
  eles(reject(data));
});

需要某個自定義的函數,變成 Promise 只需返回一個 Promise 即可

function myFun(flag) {
  return new Promise((resolve, reject) => {
    //處理操作  返回resolve或者reject
    if (flag) resolve(data);
    eles(reject(errorData));
  });
}

在具體項目中,使用 Promise 封裝獲取當前配置方法。

/**
 * 獲取字典列表
 * axios : axios
 * lang : 當前傳入語言 ,根據不同語言,獲取配置不同
 *
 * 判斷sessionStorage里是否獲取到當前所需要字典配置。
 * 如果有返回該配置,獲取不到再從接口中獲取數據,並保存到sessionStorage。
 */
function getDictionary(axios, lang) {
  // 查看sessionStorage
  const dic = sessionStorage.getItem("dictionary_data_" + lang) || null;
  // 返回一個Promise對象
  return new Promise((resolve, reject) => {
    if (dic) resolve(JSON.parse(dic));
    else {
      axios
        .get(`/api/dictionary?language=${lang}`)
        .then((res) => {
          const dic_data = {};
          if (res.data.code === 0 && res.data.result) {
            res.data.result.forEach((r) => (dic_data[r.itemName] = r));
            //存放sessionStorage
            sessionStorage.setItem(
              "dictionary_data_" + lang,
              JSON.stringify(dic_data)
            );
            // 返回數據
            resolve(dic_data);
          } else reject();
        })
        .catch((error) => reject());
    }
  });
}

靜態方法

Primise.all(iterable)

傳參需要是一個可迭代對象
Promise.all 返回一個 Promise 對象。
該 Promise 對象會在 Promise.all 的 iterable 參數對象里的所有 Promise 對象都成功才會觸發。

簡單來說就是只有 Promise.all 參數里的所有 Promise 成功才會觸發,有一個失敗就不會觸發。

例如:

var promise1 = Promise.resolve("heihei");
var promise2 = "wenbo";
var promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve([1, 2, 3]);
  }, 2000);
});

Promise.all([promise1, promise2, promise3]).then((res) => {
  console.log(res);
});

上面代碼 會在大約兩秒之后 打印輸出 [ 'heihei', 'wenbo', [ 1, 2, 3 ] ]
因為 Promise.all 需要等待 promise3 中的 setTimeout 完成后才會觸發返回 Promise 對象

又例如:

var promise1 = Promise.reject("heihei");
var promise2 = "wenbo";
var promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve([1, 2, 3]);
  }, 2000);
});

Promise.all([promise1, promise2, promise3])
  .then((res) => {
    console.log(res);
  })
  .catch((e) => {
    console.log(e);
  });

上面代碼,並不會在等待 2 秒左右輸出[ 'heihei', 'wenbo', [ 1, 2, 3 ] ],而會直接輸出heihei因為在 promise1 中返回的是一個 rejectPromise.all認為promise1失敗(rejected)。Promise.all會異步的將失敗的結果返回,而不管其它 promise 是否完成。

在某些特定的場合,需要 Promise.all 返回的數據,才讓繼續執行代碼。因為Promise.all是異步的,我們可以借助 asyncawait 實現。

var promise1 = Promise.resolve("heihei");
var promise2 = "wenbo";
var promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve([1, 2, 3]);
  }, 2000);
});

function demo() {
  Promise.all([promise1, promise2, promise3]).then((res) => {
    console.log(res);
  });
  console.log("heihei");
}
demo();

以上代碼會在執行之后 先打印"heihei",之后 2 秒左右才會打印輸出[ 'heihei', 'wenbo', [ 1, 2, 3 ] ]

var promise1 = Promise.resolve("heihei");
var promise2 = "wenbo";
var promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve([1, 2, 3]);
  }, 2000);
});

async function demo() {
  await Promise.all([promise1, promise2, promise3]).then((res) => {
    console.log(res);
  });
  console.log("heihei");
}
demo();

上方在使用了 asyncawait之后 會等在 Promise.all 執行完成之后才會打印輸出heihei。在實際項目中可以在下面使用Promise.all返回的數據進行操作。

Promise.allSettled(iterable)

傳參需要是一個可迭代對象
Promise.allSettled 返回一個 Promise 對象。
該 Promise 對象會在 Promise.allSettled 的 iterable 參數對象里的所有 Promise 對象都成功或者失敗才會觸發。

簡單說就是等所有的 Promise 執行完成才會觸發,無論成功還是失敗。

var promise1 = Promise.reject("heihei");
var promise2 = "wenbo";
var promise3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve([1, 2, 3]);
  }, 2000);
});

Promise.allSettled([promise1, promise2, promise3])
  .then((res) => {
    console.log(res);
  })
  .catch((e) => {
    console.log(e);
  });

輸出為:

[
  { status: "rejected", reason: "heihei" },
  { status: "fulfilled", value: "wenbo" },
  { status: "fulfilled", value: [1, 2, 3] },
];

可以看到Promise.allSettled的返回值為一個數組,數組里包括每個 Promise 的狀態status,返回值value,和 rejected 的值reason

Promise.all() 相比,Promise.all() 更適合彼此相互依賴或者在其中任何一個 reject 時立即結束。

Promise.any(iterable)

傳參需要是一個可迭代對象
Promise.any 返回一個 Promise 對象。
接收一個 Promise 對象的集合,當其中的一個 promise 成功,就返回那個成功的 promise 的值。

var promise1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve([4000]);
  }, 4000);
});
var promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve([1000]);
  }, 1000);
});

Promise.any([promise1, promise2])
  .then((res) => {
    console.log(res);
  })
  .catch((e) => {
    console.log(e);
  });

簡單來說, Promise.any 像是競速模式,那個 Promise 先成功,就返回哪一個 Promise

Promise.any 和 Promise.all 是相反的,一個是全部成功才觸發,一個只要有一個成功就觸發。

var promise1 = Promise.reject("error");
var promise2 = Promise.reject("error2");
Promise.any([promise1, promise2])
  .then((res) => {
    console.log(res);
  })
  .catch((e) => {
    console.log(e);
  });

//輸出

//AggregateError: All promises were rejected

如上代碼,當所有 Promise 都沒有成功時,將返回一個 Error 的 Promise

Promise.race(iterable)

傳參需要是一個可迭代對象
Promise.any 返回一個 Promise 對象。
接收一個 Promise 對象的集合,當其中的一個 promise 成功或者失敗時,就返回那個成功或者失敗的 promise 的值。

和 Promise.any 對比,Promise.any 為當有一個成功時,返回成功的 promise,Promise.race 則是不論成功失敗都返回

var promise1 = Promise.resolve("resolve");
var promise2 = Promise.reject("error");
Promise.race([promise1, promise2])
  .then((res) => {
    console.log(res); //resolve
  })
  .catch((e) => {
    console.log(e);
  });
// 輸出為resolve
var promise1 = Promise.reject("error");
var promise2 = Promise.resolve("resolve");

Promise.race([promise1, promise2])
  .then((res) => {
    console.log(res);
  })
  .catch((e) => {
    console.log(e); //error
  });

//輸出為 error

Promise.reject(reason)

返回一個狀態為失敗的 Promise 對象,並將給定的失敗信息傳遞給對應的處理方法
Promise.reject()方法返回一個帶有拒絕原因的 Promise 對象。

Promise.reject("test-reject")
  .then((res) => {
    console.log(res);
  })
  .catch((e) => {
    console.log(e); //test-reject
  });

Promise.resolve(value)

返回一個狀態由給定 value 決定的 Promise 對象

如果這個是一個 Promise 對象,則返回這 Promise 對象。
如果這個值是 thenable(即帶有"then" 方法),返回的 promise 會“跟隨”這個 thenable 的對象,采用它的最終狀態

Promise.resolve("test-resolve")
  .then((res) => {
    console.log(res); //test-resolve
  })
  .catch((e) => {
    console.log(e);
  });

當 Resolve 是一個 Promise 對象,則返回這個 Promise 對象。

var promise = Promise.resolve({
  name: "resolve",
});

Promise.resolve(promise)
  .then((res) => {
    console.log(res); //{name:resolve}
  })
  .catch((e) => {
    console.log(e);
  });
//reject情況
var promise = Promise.reject({
  name: "reject",
});

Promise.resolve(promise)
  .then((res) => {
    console.log(res);
  })
  .catch((e) => {
    console.log(e); //{name:reject}
  });

當 Resolve 是一個 thenable 對象時

var p1 = Promise.resolve({
  then: function (resolve, reject) {
    resolve("hello ~!");
  },
});
p1.then((res) => {
  console.log(res); //hello ~!
});

注意:要在解析為自身的 thenable 上調用 Promise.resolve。這將導致無限遞歸。

Promise 原型方法

Promise.prototype.catch(onRejected)

catch() 方法返回一個 Promise ,並且處理拒絕的情況
實際上 catch 的行為與調用 Promise.prototype.then(undefined, onRejected) 相同
obj.catch(onRejected) 內部 calls obj.then(undefined, onRejected)

var promise = new Promise((resolve, reject) => {
  throw "出現了錯誤~";
});
promise.then(
  (res) => {
    console.log(res);
  },
  (e) => {
    console.log(e); //出現了錯誤~
  }
);

promise
  .then((res) => {
    console.log(res);
  })
  .catch((e) => {
    console.log(e); //出現了錯誤~
  });

以上兩種方法 都可以實現異常的捕獲

Promise.prototype.then(onFulfilled, onRejected)

then() 方法返回一個 Promise。它最多需要有兩個參數:Promise 的成功和失敗情況的回調函數。

當只穿一個值得時候默認是 Promise 成功的回調函數

//默認一個參數
var promise = new Promise((resolve, reject) => {
  resolve("成功~");
  //or
  // reject('失敗~')
});

promise.then(
  (res) => {
    console.log(res); //成功~
  },
  (error) => {
    console.log(error); // 失敗~
  }
);

Promise.prototype.finally(onFinally)

finally() 方法返回一個 Promise。在 promise 結束時,無論結果是 fulfilled 或者是 rejected,都會執行指定的回調函數。這為在 Promise 是否成功完成后都需要執行的代碼提供了一種方式。
這避免了同樣的語句需要在 then()和 catch()中各寫一次的情況。

var promise = new Promise((resolve, reject) => {
  resolve("成功~");
  //or
  // reject('失敗~')
});

promise
  .then(
    (res) => {
      console.log(res); //成功~
    },
    (error) => {
      console.log(error); // 失敗~
    }
  )
  .finally((res) => {
    console.log("finally~");
  });

如以上代碼所示,無論 Promise 返回 resolve 還是 reject,都會執行 finally 里的內容。

鏈式使用

由於 promise.then(),promise.catch() 和 promise.finally()可以對已完成(成功或者失敗)的 Promise 進行操作,還會返回一個新的 Promise 對象,在新的 Promise 對象上我們還可以使用這些方法進行操作,形成一個鏈式操作。

var promise = new Promise((resolve, reject) => {
  resolve("成功~");
});

promise
  .then((res) => {
    console.log(res); //成功
    return new Promise((resolve, reject) => {
      resolve("成功01~");
    });
  })
  .then((res) => {
    console.log(res); //成功01~
    return new Promise((resolve, reject) => {
      resolve("成功02~");
    });
  })
  .then((res) => {
    console.log(res); //成功02~
    throw "error~";
  })
  .catch((e) => {
    console.log(e); //error~
  });


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM