溫馨提示×

溫馨提示×

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

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

ECMAScript6中的Promise是什么?如何使用?

發(fā)布時(shí)間:2020-05-14 13:59:18 來源:億速云 閱讀:223 作者:Leah 欄目:web開發(fā)

ECMAScript6中的Promise是什么?如何使用?這些問題可能是我們?nèi)粘9ぷ鲿?huì)見到的。通過這些問題,希望你能收獲更多。下面是揭開這些問題的詳細(xì)內(nèi)容。

Promise是什么

Promise是構(gòu)造函數(shù),可以通過new來生成Promise對(duì)象。

Promise有什么用

目前我的感受是:更加方便來操作異步流程,更加明確直觀的控制事件的流程以及可以鏈?zhǔn)秸{(diào)用

Promise特點(diǎn)

Promise對(duì)象有以下兩個(gè)特點(diǎn)。

(1)對(duì)象的狀態(tài)不受外界影響。Promise對(duì)象代表一個(gè)異步操作,有三種狀態(tài):pending(進(jìn)行中)、fulfilled(已成功)和rejected(已失敗)。只有異步操作的結(jié)果,可以決定當(dāng)前是哪一種狀態(tài),任何其他操作都無法改變這個(gè)狀態(tài)。這也是Promise這個(gè)名字的由來,它的英語意思就是“承諾”,表示其他手段無法改變。
(2)一旦狀態(tài)改變,就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果。Promise對(duì)象的狀態(tài)改變,只有兩種可能:從pending變?yōu)閒ulfilled和從pending變?yōu)閞ejected。只要這兩種情況發(fā)生,狀態(tài)就凝固了,不會(huì)再變了,會(huì)一直保持這個(gè)結(jié)果,這時(shí)就稱為 resolved(已定型)。如果改變已經(jīng)發(fā)生了,你再對(duì)Promise對(duì)象添加回調(diào)函數(shù),也會(huì)立即得到這個(gè)結(jié)果。這與事件(Event)完全不同,事件的特點(diǎn)是,如果你錯(cuò)過了它,再去監(jiān)聽,是得不到結(jié)果的。

通過幾個(gè)簡單例子理解它

通過new構(gòu)造一個(gè)簡單的Promise對(duì)象

let p = new Promise((resolve, reject) => {});

傳入的兩個(gè)參數(shù)是用來控制Promise對(duì)象的狀態(tài),我們打印一下p看一下它的狀態(tài):
Promise {__proto__: Promise[[PromiseStatus]]: "pending"[[PromiseValue]]: undefined這個(gè)就是初始狀態(tài)pending
而resolve,reject可以控制Promise的狀態(tài)

//resolve()
let p = new Promise((resolve, reject) => resolve("123")); //Promise {<resolved>: "123"}
//reject()
let p = new Promise((resolve, reject) => reject("123")); //reject()后是返回一個(gè)失敗狀態(tài)的Promise,不需要用catch來捕獲不寫catch會(huì)報(bào)錯(cuò)
p.catch(data => console.log(data));    
console.log(p);    //Promise {<rejected>: "123"}   123

提到了catch那就有還有一個(gè)then
 說一直白點(diǎn):then(f1, f2)可以填入兩個(gè)函數(shù)參數(shù),一個(gè)參數(shù)就是將resolve中參數(shù)代入f1來執(zhí)行,第二個(gè)參數(shù)將reject中參數(shù)代入f2來執(zhí)行;第二個(gè)參數(shù)可以用catch來代替,并且它更加強(qiáng)大,catch能捕獲then()中的報(bào)錯(cuò)

let p = new Promise((resolve, reject) => {
    
    let n = Math.ceil(Math.random() * 10);
    n > 5 ? resolve(n) : reject(n);
});
p.then(
    data => console.log(data),
    data => console.log(data),
)

用catch代替,并捕獲then的錯(cuò)誤

let p = new Promise((resolve, reject) => {
    
    resolve("yes")
});
p.then(
    data => {console.log(data),console.log(a)}

).catch(data => console.log(data));
//yes
//ReferenceError: a is not defined

因?yàn)閠hen處理后返回的還是Promise對(duì)象,這樣方便鏈?zhǔn)秸{(diào)用,then中都沒有return,怎么會(huì)有Promise對(duì)象的呢?

then或catch即使未顯式指定返回值, 它們也總是自動(dòng)包裝一個(gè)新的fulfilled狀態(tài)的promise對(duì)象。

我們打印一下會(huì)發(fā)現(xiàn):Promise {<resolved>: undefined}
  那么我們可以顯示的return一個(gè)Promise對(duì)象看看,

let p = new Promise((resolve, reject) => resolve("yes"));
p.then(data => Promise.resolve("第二個(gè)Promise")).then(data => console.log(data));   //第二個(gè)Promise

可以看到p.then(data => Promise.resolve("第二個(gè)Promise"))返回Promise對(duì)象是Promise {<resolved>: "第二個(gè)Promise"}并且將value值作為參數(shù)傳入到第二個(gè)then中來執(zhí)行

Promise.resolve(value | promise | thenable)創(chuàng)建Promise對(duì)象
  第一參數(shù)空或者原始值,創(chuàng)建后的Promise對(duì)象狀態(tài)直接為resolved狀態(tài)

Promise.resolve('f')
// 等價(jià)于
new Promise(resolve => resolve('f'))

第二值得注意的是具有then方法的對(duì)象

let thenable = {
    then :(resolve, reject) => resolve("thenable")
}

let p = Promise.resolve(thenable);
console.log(p);

Promise對(duì)象狀態(tài)由<pending>-><resolve>
  第三參數(shù)為實(shí)例化的Promise對(duì)象,

let p1 = new Promise((resolve, reject) => false);
let p = Promise.resolve(p1);
console.log(p);

p狀態(tài)和p1狀態(tài)一致的

Promise.reject(value)創(chuàng)建Promise對(duì)象
  與resolve不同的是:直接將value原樣作為參數(shù)傳入

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

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

catch方法的參數(shù)不是reject拋出的“出錯(cuò)了”這個(gè)字符串,而是thenable對(duì)象。

Promise.all

將多個(gè) Promise 實(shí)例,包裝成一個(gè)新的 Promise 實(shí)例;const p = Promise.all([p1, p2, p3]);

(1)只有p1、p2、p3的狀態(tài)都變成fulfilled,p的狀態(tài)才會(huì)變成fulfilled,此時(shí)p1、p2、p3的返回值組成一個(gè)數(shù)組,傳遞給p的回調(diào)函數(shù)。

(2)只要p1、p2、p3之中有一個(gè)被rejected,p的狀態(tài)就變成rejected,此時(shí)第一個(gè)被reject的實(shí)例的返回值,會(huì)傳遞給p的回調(diào)函數(shù)。

會(huì)等all中的對(duì)象全部執(zhí)行完后將數(shù)組傳入回調(diào)函數(shù)then中

let p = new Promise((resolve, reject) => setTimeout(() => resolve('p'),1000));
let p1 = new Promise((resolve, reject) => setTimeout(() => resolve('p2'),2000));
let p2 = new Promise((resolve, reject) => setTimeout(() => resolve('p3'),3000));
Promise.all([p, p1, p2]).then(data => console.log(data)).catch(data => console.log(data));    // ["p", "p2", "p2"]
let p = new Promise((resolve, reject) => resolve('p'));
let p1 = new Promise((resolve, reject) => reject('p2'));
let p2 = new Promise((resolve, reject) => resolve('p2'));
Promise.all([p, p1, p2]).then(data => console.log(data)).catch(data => console.log(data));   //p2

Promise.race
與all不同的是:只要p1、p2、p3之中有一個(gè)實(shí)例率先改變狀態(tài),p的狀態(tài)就跟著改變。那個(gè)率先改變的 Promise 實(shí)例的返回值,就傳遞給p的回調(diào)函數(shù)。

let p = new Promise((resolve, reject) => setTimeout(() => resolve('p'),1000));
let p1 = new Promise((resolve, reject) => setTimeout(() => resolve('p2'),2000));
let p2 = new Promise((resolve, reject) => setTimeout(() => resolve('p3'),3000));
Promise.race([p, p1, p2]).then(data => console.log(data)).catch(data => console.log(data));   //p

Promise對(duì)象的回調(diào)函數(shù)與setTimeout的順序問題

An event loop has one or more task queues. A task queue is an ordered list of tasks, which are algorithms that are responsible for such work as: events, parsing, callbacks, using a resource, reacting to DOM manipulation…Each event loop has a microtask queue. A microtask is a task that is originally to be queued on the microtask queue rather than a task queue.
  瀏覽器(或宿主環(huán)境) 遵循隊(duì)列先進(jìn)先出原則, 依次遍歷macrotask queue中的每一個(gè)task, 不過每執(zhí)行一個(gè)macrotask, 并不是立即就執(zhí)行下一個(gè), 而是執(zhí)行一遍microtask queue中的任務(wù), 然后切換GUI線程重新渲染或垃圾回收等.
  Event Loop (事件循環(huán))擁有如下兩種隊(duì)列
  macrotask queue, 指的是宏任務(wù)隊(duì)列, 包括rendering, script(頁面腳本), 鼠標(biāo), 鍵盤, 網(wǎng)絡(luò)請求等事件觸發(fā), setTimeout, setInterval, setImmediate(node)等等.
  microtask queue, 指的是微任務(wù)隊(duì)列, 用于在瀏覽器重新渲染前執(zhí)行, 包含Promise, process.nextTick(node), Object.observe, MutationObserver回調(diào)等.
  process.nextTick > promise.then > setTimeout ? setImmediate

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');

// one
// two
// three

上面代碼中,setTimeout(fn, 0)在下一輪“事件循環(huán)”開始時(shí)執(zhí)行,Promise.resolve()在本輪“事件循環(huán)”結(jié)束時(shí)執(zhí)行,console.log('one')則是立即執(zhí)行,因此最先輸出。

setTimeout(function() {
  console.log(4)
}, 0);
new Promise(function(resolve) {
  console.log(1);
  for (var i = 0; i < 10000; i++) {
    i == 9999 && resolve()
  }
  console.log(2);
}).then(function() {
  console.log(5)
});
console.log(3);  //1 2 3 5 4

以上就是ECMAScript6中Promise的詳細(xì)內(nèi)容了,看完之后是否有所收獲呢?如果想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI