中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Promise如何在Javascript中使用

發布時間:2021-04-01 17:24:34 來源:億速云 閱讀:158 作者:Leah 欄目:web開發

本篇文章為大家展示了Promise如何在Javascript中使用,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

什么是 Promise?

首先我們來了解 Promise 到底是怎么一回事

Promise 是抽象的異步處理對象,以及對其進行各種操作的組件。我知道這樣解釋你肯定還是不明白 Promise 是什么東西,你可以把 Promise 理解成一個 容器,里面裝著將來才會結束的一個事件的結果,這個事件通常是一個異步操作。

Promise最初被提出是在 E語言中, 它是基于并列/并行處理設計的一種編程語言。Javascript 在 ES6 之后也開始支持 Promise 特性了,用來解決異步操 的問題。這里順便解釋一下什么是 ES6, ECMAScript 是 Javascript 語言的國際標準,Javascript 是 ECMAScript 的有一個實現, 而ES6(全稱 ECMAScript 6)是這個標準的一個版本。

3、Javascript 為什么要引入 Promise?

細心的你可能發現了我剛剛說了 Javascript 支持 Promise 實現是為了解決異步操作的問題。談到異步操作,你可能會說,Javascript 不是可以用回調 函數處理異步操作嗎? 原因就是 Promise 是一種更強大的異步處理方式,而且她有統一的 API 和規范,下面分別看看傳統處理異步操作和 Promise 處理 異步操作有哪些不同。

使用回調函數處理異步操作:

login("http://www.r9it.com/login.php", function(error, result){
  // 登錄失敗處理
 if(error){
    throw error;
  }
  // 登錄成功時處理
});

Node.js等則規定在JavaScript的回調函數的第一個參數為 Error 對象,這也是它的一個慣例。 像上面這樣基于回調函數的異步處理如果統一參數使用規則的話,寫法也會很明了。 但是,這也僅是編碼規約而已,即使采用不同的寫法也不會出錯。 而Promise則是把類似的異步處理對象和處理規則進行規范化, 并按照采用統一的接口來編寫,而采取規定方法之外的寫法都會出錯。

使用 Promise 處理異步操作:

var promise = loginByPromise("http://www.r9it.com/login.php"); 
promise.then(function(result){
  // 登錄成功時處理
}).catch(function(error){
  // 登錄失敗時處理
});

通過上面兩個 demo 你會發現,有了Promise對象,就可以將異步操作以同步操作的流程表達出來。 這樣在處理多個異步操作的時候還可以避免了層層嵌套的回調函數(后面會有演示)。 此外,Promise對象提供統一的接口,必須通過調用 Promise#then Promise#catch 這兩個方法來結果,除此之外其他的方法都是不可用的,這樣使得異步處理操作更加容易。

4、基本用法

在 ES6 中,可以使用三種辦法創建 Promise 實例(對象)

(1). 構造方法

let promies = new Promise((resolve, reject) => {
 resolve(); //異步處理 
});

Promise 構造函數接受一個函數作為參數,該函數的兩個參數分別是 resolve 和 reject。它們是兩個函數,由 JavaScript 引擎提供,不用自己部署。

(2). 通過 Promise 實例的方法,Promise#then 方法返回的也是一個 Promise 對象

promise.then(onFulfilled, onRejected);

(3). 通過 Promise 的靜態方法,Promise.resolve(),Promise.reject()

var p = Promise.resolve();
p.then(function(value) {
 console.log(value); 
});

4.1 Promise 的執行流程

  1. new Promise構造器之后,會返回一個promise對象;

  2. 為 promise 注冊一個事件處理結果的回調函數(resolved)和一個異常處理函數(rejected);

4.2 Promise 的狀態

實例化的 Promise 有三個狀態:

Fulfilled: has-resolved, 表示成功解決,這時會調用 onFulfilled.

Rejected: has-rejected, 表示解決失敗,此時會調用 onRejected.

Pending: unresolve, 表示待解決,既不是resolve也不是reject的狀態。也就是promise對象剛被創建后的初始化狀態.

上面我們提到 Promise 構造函數接受一個函數作為參數,該函數的兩個參數分別是 resolve 和 reject.

resolve函數的作用是,將 Promise 對象的狀態從 未處理 變成 處理成功 (unresolved => resolved), 在異步操作成功時調用,并將異步操作的結果作為參數傳遞出去。

reject函數的作用是,將 Promise 對象的狀態從 未處理 變成 處理失敗 (unresolved => rejected), 在異步操作失敗時調用,并將異步操作報出的錯誤,作為參數傳遞出去。

Promise 實例生成以后,可以用 then 方法和 catch 方法分別指定 resolved 狀態和 rejected 狀態的回調函數。

以下是 Promise 的狀態圖

Promise如何在Javascript中使用

4.3 Promise 的基本特性

【1】 對象的狀態不受外界影響 Promise 對象代表一個異步操作,有三種狀態:pending(進行中)、fulfilled(已成功)和rejected(已失敗)。 只有異步操作的結果,可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態。 這也是Promise這個名字的由來,它的英語意思就是“承諾”,表示其他手段無法變。

【2】 一旦狀態改變,就不會再變,任何時候都可以得到這個結果 Promise對象的狀態改變,只有兩種可能:從 pending 變為 fulfilled 和從 pending 變為 rejected。 只要這兩種情況發生,狀態就凝固了,不會再變了,會一直保持這個結果,這時就稱為 resolved(已定型)。 如果改變已經發生了,你再對 Promise 對象添加回調函數,也會立即得到這個結果。 這與事件(Event)完全不同,事件的特點是,如果你錯過了它,再去監聽,是得不到結果的。

例如以下代碼, reject 方法是無效的

var promise = new Promise((fuck, reject) => {
 resolve("xxxxx");
 //下面這行代碼無效,因為前面 resolve 方法已經將 Promise 的狀態改為 resolved 了
 reject(new Error()); 
});

promise.then((value) => { 
 console.log(value);
})

下圖是 Promise 的狀態處理流程圖

Promise如何在Javascript中使用

5、Promise 的執行順序

我們知道 Promise 在創建的時候是立即執行的,但是事實證明 Promise 只能執行異步操作,即使在創建 Promise 的時候就立即改變它狀態。

var p = new Promise((resolve, reject) => {
 console.log("start Promise");
 resolve("resolved"); 
});

p.then((value) => {
 console.log(value);
}) 

console.log("end Promise");

打印的結果是:

start Promise
end Promise
resolved

或許你會問,這個操作明明是同步的,定義 Promise 里面的代碼都被立即執行了,那么回調應該緊接著 resolve 函數執行,那么應該先打印 “resolved” 而不應該先打印 “end Promise”.

這個是 Promise 規范規定的,為了防止同步調用和異步調用同時存在導致的混亂

6、Promise 的鏈式調用(連貫操作)

前面我們講過,Promise 的 then 方法以及 catch 方法返回的都是新的 Promise 對象,這樣我們可以非常方便的解決嵌套的回調函數的問題, 也可以很方便的實現流程任務。

var p = new Promise(function(resolve, reject) {
  resolve();
});
function taskA() {
  console.log("Task A");
}
function taskB() {
  console.log("Task B");
}
function taskC() {
  console.log("Task C");
}
p.then(taskA())
.then(taskB())
.then(taskC())
.catch(function(error) {
  console.log(error);
});

上面這段代碼很方便的實現了從 taskA 到 taskC 的有序執行。

當然你可以把 taskA - taskC 換成任何異步操作,如從后臺獲取數據:

var getJSON = function(url, param) {
 var promise = new Promise(function(resolve, reject){
 var request = require('ajax-request');
 request({url:url, data: param}, function(err, res, body) {
  if (!err && res.statusCode == 200) {
  resolve(body);
  } else {
  reject(new Error(err));
  }
 });
 });

 return promise;
};
var url = "login.php";
getJSON(url, {id:1}).then(result => {
 console.log(result);
 return getJSON(url, {id:2})
}).then(result => {
 console.log(result);
 return getJSON(url, {id:3});
}).then(result => {
 console.log(result);
}).catch(error => console.log(error));

這樣用起來似乎很爽,但是有個問題需要注意,我們說過每個 then() 方法都返回一個新的 Promise 對象,那既然是 Promise 對象,那肯定就有注冊 onFulfilled 和 onRejected, 如果某個任務流程的 then() 方法鏈過長的話,前面的任務拋出異常,會導致后面的任務被跳過。

function taskA() {
  console.log("Task A");
  throw new Error("throw Error @ Task A");
}
function taskB() {
  console.log("Task B");
}
function onRejected(error) {
  console.log(error);
}
function finalTask() {
  console.log("Final Task");
}
var promise = Promise.resolve();
promise
  .then(taskA)
  .then(taskB)
  .catch(onRejected)
  .then(finalTask);

執行的結果是:

Task A
Error: throw Error @ Task A
Final Task

顯然, 由于 A 任務拋出異常(執行失敗),導致 .then(taskB) 被跳過,直接進入 .catch 異常處理環節。

6.1 promise chain 中如何傳遞參數

上面我們簡單闡述了 Promise 的鏈式調用,能夠非常有效的處理異步的流程任務。

但是在實際的使用場景中,任務之間通常都是有關聯的,比如 taskB 需要依賴 taskA 的處理結果來執行,這有點類似 Linux 管道機制。 Promise 中處理這個問題也很簡單,那就是在 taskA 中 return 的返回值,會在 taskB 執行時傳給它。

function taskA() {
  console.log("Task A");
  return "From Task A";
}
function taskB(value) {
 console.log(value);
  console.log("Task B");
  return "From Task B";
}
function onRejected(error) {
  console.log(error);
}
function finalTask(value) {
 console.log(value);
  console.log("Final Task");
}
var promise = Promise.resolve();
promise
  .then(taskA)
  .then(taskB)
  .catch(onRejected)
  .then(finalTask);

搞定,就這么簡單!

6.2 resolve 和 reject 參數

reject函數的參數通常是Error對象的實例,表示拋出的錯誤;resolve函數的參數除了正常的值以外,還可能是另一個 Promise 實例, 比如像上面的 getJSON() 方法一樣。

var p1 = new Promise(function (resolve, reject) {
 setTimeout(() => reject(new Error('fail')), 3000)
})

var p2 = new Promise(function (resolve, reject) {
 setTimeout(() => resolve(p1), 1000)
})

p2
 .then(result => console.log(result))
 .catch(error => console.log(error))

注意,這時p1的狀態就會傳遞給p2,也就是說,p1的狀態決定了p2的狀態。

如果p1的狀態是 pending,那么p2的回調函數就會等待p1的狀態改變;

如果p1的狀態已經是 resolved 或者 rejected,那么p2的回調函數將會立刻執行。

7、Promise 基本方法

ES6的Promise API提供的方法不是很多,下面介紹一下 Promise 對象常用的幾個方法.

7.1 Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)的別名,用于指定發生錯誤時的回調函數。

p.then((val) => console.log('fulfilled:', val))
 .catch((err) => console.log('rejected', err));

// 等同于
p.then((val) => console.log('fulfilled:', val))
 .then(null, (err) => console.log("rejected:", err));

Promise 對象的錯誤具有“冒泡”性質,會一直向后傳遞,直到被捕獲為止。也就是說,錯誤總是會被下一個catch語句捕獲。 所以通常建議使用 catch 方法去捕獲異常,而不要用 then(null, function(error) {}) 的方式,因為這樣只能捕獲當前 Promise 的異常

p.then(result => {console.log(result)})
 .then(result => {console.log(result)})
 .then(result => {console.log(result)})
 .catch(error => {
  //捕獲上面三個 Promise 對象產生的異常
  console.log(error);
 });

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

通俗的說法就是“Promise 會吃掉錯誤”。

比如下面的代碼就出現這種情況

var p = new Promise(function(resolve, reject) {
  // 下面一行會報錯,因為x沒有聲明
  resolve(x + 2);
 });
p.then(() => {console.log("every thing is ok.");});
// 這行代碼會正常執行,不會受 Promise 里面報錯的影響
console.log("Ok, it's Great.");

7.2 Promise.all()

Promise.all方法用于將多個 Promise 實例,包裝成一個新的 Promise 實例。用來處理組合 Promise 的邏輯操作。

var p = Promise.all([p1, p2, p3]);

上面代碼 p 的狀態由p1、p2、p3決定,分成兩種情況。

  1. 只有p1、p2、p3的狀態都變成fulfilled,p的狀態才會變成fulfilled,此時p1、p2、p3的返回值組成一個數組,傳遞給p的回調函數。

  2. 只要p1、p2、p3之中有一個被rejected,p的狀態就變成rejected,此時第一個被reject的實例的返回值,會傳遞給p的回調函數。

下面是一個具體的例子

// 生成一個Promise對象的數組
var promises = [1,2,3,4,5,6].map(function (id) {
 return getJSON('/post/' + id + ".json");
});

Promise.all(promises).then(function (posts) {
 // ...
}).catch(function(reason){
 // ...
});

上面代碼中,promises 是包含6個 Promise 實例的數組,只有這6個實例的狀態都變成 fulfilled,或者其中有一個變為 rejected, 才會調用 Promise.all 方法后面的回調函數。

7.3 Promise.race()

Promise.race方法同樣是將多個Promise實例,包裝成一個新的Promise實例。 與 Promise.all 不同的是,只要有一個 promise 對象進入 FulFilled 或者 Rejected 狀態的話,Promise.rece 就會繼續進行后面的處理

var p = Promise.race([p1, p2, p3]);

上面代碼中,只要p1、p2、p3之中有一個實例率先改變狀態,p的狀態就跟著改變。那個率先改變的 Promise 實例的返回值,就傳遞給p的回調函數。 Promise.race 方法的參數與 Promise.all 方法一樣,如果不是 Promise 實例,就會先調用 Promise.resolve 方法, 將參數轉為 Promise 實例,再進一步處理。

下面是一個具體的例子

// `delay`毫秒后執行resolve
function timerPromisefy(delay) {
  return new Promise(function (resolve) {
    setTimeout(function () {
      resolve(delay);
    }, delay);
  });
}
// 任何一個promise變為resolve或reject 的話程序就停止運行
Promise.race([
  timerPromisefy(1),
  timerPromisefy(32),
  timerPromisefy(64),
  timerPromisefy(128)
]).then(function (value) {
  console.log(value);  // => 1
});

7.4 Promise.resolve()

Promise.resolve 方法有2個作用,一個就是前面我們說的,它是通過靜態方法創建 Promise 實例的渠道之一, 另一個作用就是將 Thenable 對象轉換為 Promise 對象。

那么什么是 Thenable 對象呢?ES6 Promises里提到了Thenable這個概念,簡單來說它就是一個非常類似promise的東西。 就像我們有時稱具有 .length 方法的非數組對象為 Array like 一樣,Thenable 指的是一個具有 .then 方法的對象。

這種將 Thenable對象轉換為 Promise 對象的機制要求thenable對象所擁有的 then 方法應該和Promise所擁有的 then 方法具有同樣的功能和處理過程, 在將 Thenable 對象轉換為 Promise 對象的時候,還會巧妙的利用 Thenable 對象原來具有的 then 方法。

到底什么樣的對象能算是 Thenable 的呢,最簡單的例子就是 jQuery.ajax(),它的返回值就是 Thenable 的。

將 Thenable 對象轉換為 Promise 對象

var promise = Promise.resolve($.ajax('/json/comment.json'));// => promise對象
promise.then(function(value){
  console.log(value);
});

除了上面的方法之外,Promise.resolve方法的參數還有以下三種情況。

(1). 參數是一個 Promise 實例

如果參數是Promise實例,那么Promise.resolve將不做任何修改、原封不動地返回這個實例。

(2). 參數不是具有then方法的對象,或根本就不是對象

如果參數是一個原始值,或者是一個不具有then方法的對象,則Promise.resolve方法返回一個新的Promise對象,狀態為resolved。

var p = Promise.resolve('Hello');
p.then(function (s){
 console.log(s)
});

上面代碼生成一個新的Promise對象的實例p。由于字符串Hello不屬于異步操作(判斷方法是字符串對象不具有then方法), 返回Promise實例的狀態從一生成就是resolved,所以回調函數會立即執行。 Promise.resolve方法的參數,會同時傳給回調函數。

(3). 不帶有任何參數

Promise.resolve方法允許調用時不帶參數,直接返回一個resolved狀態的Promise對象。這個我們在上面講創建 Promise 實例的三種方法的時候就講過了

var p = Promise.resolve();
p.then(function () {
 // ...
});

7.5 Promise.reject()

Promise.reject(reason)方法也會返回一個新的 Promise 實例,該實例的狀態為rejected。 需要注意的是,Promise.reject()方法的參數,會原封不動地作為 reject 的理由,變成后續方法的參數。這一點與 Promise.resolve 方法不一致。

const thenable = {
 then(resolve, reject) {
  reject('出錯了');
 }
};

Promise.reject(thenable)
.catch(e => {
 console.log(e === thenable)
})
// true

上面代碼中,Promise.reject 方法的參數是一個 thenable 對象,執行以后,后面 catch 方法的參數不是 reject 拋出的“出錯了”這個字符串, 而是 thenable 對象。

上述內容就是Promise如何在Javascript中使用,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

和静县| 成武县| 海口市| 陵川县| 许昌市| 开封县| 昌图县| 乐安县| 阳泉市| 石泉县| 砚山县| 汶上县| 墨江| 新郑市| 庆阳市| 澄城县| 清流县| 望江县| 中江县| 阿拉善盟| 云阳县| 精河县| 常熟市| 新乡县| 鹿泉市| 榆社县| 颍上县| 濉溪县| 金寨县| 寿光市| 松桃| 额敏县| 白朗县| 清镇市| 汉寿县| 津市市| 铜鼓县| 土默特右旗| 平遥县| 惠东县| 濉溪县|