成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Promise介紹--規(guī)范篇

tylin / 697人閱讀

摘要:規(guī)范中對(duì)于構(gòu)造函數(shù)沒有明確說(shuō)明,所以在此處拿出來(lái)講解一下。構(gòu)造函數(shù)只接收一個(gè)參數(shù),且該參數(shù)必須是一個(gè)函數(shù),任何其他的值比如等都會(huì)報(bào)一個(gè)的錯(cuò)誤。

本篇文章是Promise系列文章的第二篇,主要是講解基于Promise/A+規(guī)范,在傳入不同類型的參數(shù)時(shí),promise內(nèi)部分別會(huì)如何處理。本章的主要目的是讓大家對(duì)promise有一個(gè)更加深入的理解,也為下一篇講如何實(shí)現(xiàn)一個(gè)promise庫(kù)做準(zhǔn)備。(寫完之后覺得好水。。。)

英文版本的規(guī)范見這里,segmentfault上也有人把規(guī)范翻譯為中文,見這里。

在此,我主要是通過使用例子,講解一下規(guī)范中then方法和Promise Resolution Procedure的每一種情況。

constructor

規(guī)范中對(duì)于構(gòu)造函數(shù)沒有明確說(shuō)明,所以在此處拿出來(lái)講解一下。

和普通JavaScript對(duì)象一樣,我們同樣是通過new關(guān)鍵詞來(lái)創(chuàng)建一個(gè)Promise對(duì)象實(shí)例。構(gòu)造函數(shù)只接收一個(gè)參數(shù),且該參數(shù)必須是一個(gè)函數(shù),任何其他的值比如undefinednull、5、true等都會(huì)報(bào)一個(gè)TypeError的錯(cuò)誤。例:

new Promise(true)
// Uncaught TypeError: Promise resolver true is not a function(…)

同樣,如果你沒有通過new關(guān)鍵詞創(chuàng)建,而是直接執(zhí)行Promise(),同樣也會(huì)報(bào)一個(gè)TypeError的錯(cuò)誤。

Promise()
// Uncaught TypeError: undefined is not a promise(…)

所以,我們必須通過new Promise(function()=>{})的方式來(lái)創(chuàng)建一個(gè)Promise實(shí)例。通常我們見到的創(chuàng)建一個(gè)Promise實(shí)例的代碼如下:

var promise = new Promise(function(resolve, reject) {
    // 進(jìn)行一些異步操作
    // 然后調(diào)用resolve或reject方法
});

這才是正確的姿勢(shì)~ 從該例子中,我們可以看到創(chuàng)建Promise實(shí)例時(shí)傳入的函數(shù),同時(shí)還接受兩個(gè)參數(shù),它們分別對(duì)應(yīng)Promise內(nèi)部實(shí)現(xiàn)的兩個(gè)方法。上一篇文章中,我提到過Promise有三種狀態(tài),pending、fulfilled、rejected,實(shí)例剛創(chuàng)建時(shí)處于pending狀態(tài),當(dāng)執(zhí)行reject方法時(shí),變?yōu)?b>rejected狀態(tài),如下所示:

new Promise(function(resolve, reject){
    reject(Promise.resolve(5))
}).then(function(value){
    console.log("fulfill", value)
}, function(reason){
    console.log("reject", reason)
})
// reject Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 5}

而當(dāng)執(zhí)行resolve方法時(shí),它可能變?yōu)?b>fulfilled,也有可能變?yōu)?b>rejected狀態(tài)。也就是說(shuō)resolve != fulfill。如下:

new Promise(function(resolve, reject){
    resolve(Promise.reject(5))
}).then(function(value){
    console.log("fulfill", value)
}, function(reason){
    console.log("reject", reason)
})
// reject 5

那么resolve是個(gè)什么東西呢?它是根據(jù)什么變?yōu)?b>fulfilled或rejected的呢?這就是我們接下來(lái)要講解的Promise Resolution Procedure,我把它稱作“Promise處理程序”。

Promise Resolution Procedure

講之前,我們先說(shuō)幾個(gè)promise規(guī)范中的幾個(gè)術(shù)語(yǔ)。

promise 它是一個(gè)擁有then方法的對(duì)象或函數(shù),且符合該規(guī)范
thenable 擁有then方法的對(duì)象或函數(shù)
value 是指一個(gè)合法的 Javascript
exception throw語(yǔ)句拋出的異常
reason 描述promise為什么失敗的值

Promise Resolution Procedure是對(duì)傳入的promise和value進(jìn)行抽象操作。我們可一個(gè)把它理解成resolve(promise, value),對(duì)參數(shù)promise和value進(jìn)行一系列處理操作。下面我們按照規(guī)范中的順序,依次介紹每種情況。

2.3.1 如果promisevalue指向同一個(gè)對(duì)象,則rejectpromise并以一個(gè)TypeError作為reason。

var defer = {}
var promise = new Promise(function(resolve){ 
    defer.resolve = resolve
})
promise.catch(function(reason){
    console.log(reason)
})
defer.resolve(promise)
// TypeError: Chaining cycle detected for promise #(…)

我們把resolve函數(shù)保存在defer中,這樣就可以在外部對(duì)promise進(jìn)行狀態(tài)改變,defer.resolve(promise)中的promise正是我們創(chuàng)建的對(duì)象,根據(jù)規(guī)范拋出了TypeError。

2.3.2 如果value是一個(gè)promise對(duì)象,且是基于當(dāng)前實(shí)現(xiàn)創(chuàng)建的。

2.3.2.1 如果value處于pending狀態(tài),則promise同樣pending并直到value狀態(tài)改變。
2.3.2.2 如果value處于fulfilled狀態(tài),則使用相同的value值fulfill promise。
2.3.2.3 如果value處于rejected狀態(tài),則使用相同的reason值reject promise。

var promise1 = new Promise((resolve) => {
    setTimeout(() => {
        resolve(5)
    },3000)
});
console.time("fulfill")
var promise = new Promise((resolve) => {
    resolve(promise1)
})
promise.then((value) => {
    console.timeEnd("fulfill")
    console.log("fulfill", value)
})
setTimeout(()=>{
    console.log("setTimeout", promise)
}, 1000)

// setTimeout Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// fulfill: 3.01e+03ms
// fulfill 5

通過該例子可以看出,最后setTimeout延遲1秒查看promise狀態(tài)時(shí),它依然處于pending狀態(tài),當(dāng)3秒后promise1變?yōu)?b>fulfilled后,promise隨即變?yōu)?b>fulfilled并以5作為value傳給then添加的成功回調(diào)函數(shù)中。

var promise1 = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject(new Error("error"))
    }, 3000)
});
console.time("reject")
var promise = new Promise((resolve) => {
    resolve(promise1)
})
promise.catch((reason) => {
    console.timeEnd("reject")
    console.log("reject", reason)
})
setTimeout(()=>{
    console.log("setTimeout", promise)
}, 1000)

// setTimeout Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// reject: 3e+03ms
// reject Error: error(…)

失敗時(shí)例子與成功時(shí)類似。

2.3.3 如果value是一個(gè)對(duì)象或函數(shù)
2.3.3.1 使then等于value.then
2.3.3.2 如果獲取value.then的值時(shí)拋出異常,這通過該異常reject promise,例:

new Promise((resolve)=>{
    resolve({then:(()=>{
        throw new Error("error")
        })()
    })
}).catch((reason)=>{
    console.log(reason)
})
// Error: error(…)

上例中獲取value.then時(shí),會(huì)拋出異常

2.3.3.3 如果then是一個(gè)函數(shù),則把value作為函數(shù)中this指向來(lái)調(diào)用它,第一個(gè)參數(shù)是resolvePromise,第二個(gè)參數(shù)是rejectPromise

其實(shí)這里主要是為了兼容兩種情況,第一種是傳入的value是個(gè)Deferred對(duì)象,則狀態(tài)和Deferred對(duì)象一致;另一種情況是不是使用當(dāng)前構(gòu)造函數(shù)創(chuàng)建的Promise對(duì)象,通過這種方式可以兼容,達(dá)到一致的效果。

2.3.3.3.1 如果resolvePromise通過傳入y來(lái)調(diào)用,則執(zhí)行resolve(promise, y),例:

new Promise((resolve)=>{
    resolve({then:(resolvePromise, rejectPromise)=>{
        resolvePromise(5)
        }
    })
}).then((value)=>{
    console.log(value)
})
// 5

2.3.3.3.2 如果rejectPromise 通過傳入原因r來(lái)調(diào)用,則傳入r來(lái)reject promise,例:

new Promise((resolve)=>{
    resolve({then:(resolvePromise, rejectPromise)=>{
        rejectPromise(new Error("error"))
        }
    })
}).catch((reason)=>{
    console.log(reason)
})
// Error: error(…)

2.3.3.3.3 如果resolvePromiserejectPromise都被調(diào)用,或其中一個(gè)被調(diào)用了多次,則以第一次調(diào)用的為準(zhǔn),并忽略之后的調(diào)用。例:

new Promise((resolve)=>{
    resolve({then:(resolvePromise, rejectPromise)=>{
        resolvePromise(5)
        rejectPromise(new Error("error"))
        }
    })
}).then((value)=>{
    console.log(value)
}, (reason)=>{
    console.log(reason)
})
// 5

2.3.3.3.4 如果調(diào)用then拋出異常e:

2.3.3.3.4.1 如果resolvePromiserejectPromise已經(jīng)調(diào)用,則忽略它,例:

new Promise((resolve)=>{
    resolve({then:(resolvePromise, rejectPromise)=>{
        resolvePromise(5)
        throw new Error("error")
        }
    })
}).then((value)=>{
    console.log(value)
}, (reason)=>{
    console.log(reason)
})
// 5

2.3.3.3.4.2 否則,則傳入e來(lái)reject promise,例:

new Promise((resolve)=>{
    resolve({then:(resolvePromise, rejectPromise)=>{
        throw new Error("error")
        }
    })
}).then((value)=>{
    console.log(value)
}, (reason)=>{
    console.log(reason)
})
// Error: error(…)

2.3.3.4 如果then不是一個(gè)函數(shù),則傳入value來(lái)fulfill promise,例:

new Promise((resolve)=>{
    resolve({then:5})
}).then((value)=>{
    console.log(value)
}, (reason)=>{
    console.log(reason)
})
// Object {then: 5}
then 方法

一個(gè)promise必須提供一個(gè)then方法來(lái)處理成功或失敗。

then方法接收兩個(gè)參數(shù):

promise.then(onFulfilled, onRejected)

2.2.1 onFulfilledonRejected都是可選的
2.2.1.1 如果onFulfilled不是一個(gè)函數(shù),則忽略。例:

Promise.resolve(5)
    .then(true,function(reason){
        console.log(reason)
    })
    .then(function(value){
        console.log(value)
    })
// 5

2.2.1.2 如果onRejected不是一個(gè)函數(shù),則忽略。例:

Promise.reject(new Error("error"))
    .then(true,null)
    .then(undefined,function(reason){
        console.log(reason)
    })

// Error: error(…)

2.2.2 如果onFulfilled是一個(gè)函數(shù)
2.2.2.1 它必須在promise變?yōu)?b>fulfilled之后調(diào)用,且把promisevalue作為它的第一個(gè)參數(shù)

這個(gè)從我們所有的例子中都可以看出

2.2.2.2 它不可以在promise變?yōu)?b>fulfilled之前調(diào)用

var defer = {}
console.time("fulfill")
var promise = new Promise((resolve)=>{
    defer.resolve = resolve
});
promise.then((value)=>{
    console.timeEnd("fulfill")
})
setTimeout(()=>{
    defer.resolve(5)
},1000);
// fulfill: 1e+03ms  

onFulfilled執(zhí)行的時(shí)間可以看出promise直到變?yōu)?b>fulfilled后才調(diào)用

2.2.2.3 它只可以被調(diào)用一次

var defer = {}
var promise = new Promise((resolve)=>{
    defer.resolve = resolve
});
promise.then((value)=>{
    console.log(value++)
})
defer.resolve(5)
// 5
defer.resolve(6)
// 后面不再次執(zhí)行

2.2.3 如果onRejected是一個(gè)函數(shù)
2.2.3.1 它必須在promise變?yōu)?b>rejected之后調(diào)用,且把promisereason作為它的第一個(gè)參數(shù)
2.2.3.2 它不可以在promise變?yōu)?b>rejected之前調(diào)用
2.2.3.3 它只可以被調(diào)用一次

onRejectedonFulfilled基本類似,這里不再次贅述

2.2.4 onFulfilledonRejected是在執(zhí)行環(huán)境中僅包含平臺(tái)代碼時(shí)調(diào)用

這里有一個(gè)備注,平臺(tái)代碼是指引擎、執(zhí)行環(huán)境、以及promise的實(shí)現(xiàn)代碼。實(shí)際過程中,要確保onFulfilledonRejected是異步執(zhí)行的,它是在event loop過程中then方法被調(diào)用之后的新調(diào)用棧中執(zhí)行。我們可以使用setTimeoutsetImmediatemacro-task機(jī)制來(lái)實(shí)現(xiàn),也可以使用MutationObserverprocess.nextTickmicro-task機(jī)制來(lái)實(shí)現(xiàn)。promise的實(shí)現(xiàn)本身就被看作是平臺(tái)代碼,它本身就包含一個(gè)處理器可以調(diào)用的任務(wù)調(diào)度隊(duì)列。

才疏學(xué)淺,沒理解它這一條到底要表達(dá)一個(gè)什么意思。。。應(yīng)該指的就是異步執(zhí)行,因?yàn)楫惒綀?zhí)行的時(shí)候,頁(yè)面中同步的邏輯都已經(jīng)執(zhí)行完畢,所以只剩下平臺(tái)代碼。

注:原生的Promise實(shí)現(xiàn)屬于micro-task機(jī)制。macro-taskmicro-task分別是兩種異步任務(wù),它們的不同后面會(huì)多帶帶講一下。下面列出了常見的異步方法都屬于那種異步機(jī)制:

macro-task: script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task: process.nextTick, 原生Promise, Object.observe, MutationObserver

2.2.5 onFulfilledonRejected必須作為函數(shù)來(lái)調(diào)用,沒有this

Promise.resolve(5).then(function(){
    console.log(this)
})
// Window {speechSynthesis: SpeechSynthesis, caches: CacheStorage, localStorage: Storage, sessionStorage: Storage, webkitStorageInfo: DeprecatedStorageInfo…}

2.2.6 同一個(gè)promise上的then方法可能會(huì)調(diào)用多次
2.2.6.1 如果promise fulfilled,則所有的onFulfilled回調(diào)函數(shù)按照它們添加的順序依次調(diào)用。

var defer = {}
var promise = new Promise((resolve)=>{
    defer.resolve = resolve
});
promise.then((value)=>{
    console.log(1,value++)
})
promise.then((value)=>{
    console.log(2,value++)
})
promise.then((value)=>{
    console.log(3,value++)
})
defer.resolve(5)

// 1 5
// 2 5
// 3 5

2.2.6.2 如果promise rejected,則所有的onRejected回調(diào)函數(shù)按照它們添加的順序依次調(diào)用。

例子與上例類似

2.2.7 then方法會(huì)返回一個(gè)全新的promise

promise2 = promise1.then(onFulfilled, onRejected);

2.2.7.1 如果onFulfilledonRejected返回了一個(gè)值x,則執(zhí)行resolve(promise2, x)

Promise.resolve(5).then(function(value){
    return ++value
}).then(function(value){
    console.log(value)
})
// 6

2.2.7.2 如果onFulfilledonRejected拋出了異常e,則reject promise2并傳入原因e

Promise.resolve(5).then(function(value){
    throw new Error("error")
}).catch(function(reason){
    console.log(reason)
})
// Error: error(…)

2.2.7.3 如果onFulfilled不是一個(gè)函數(shù)且promise1 fulfilled,則promise2以同樣的value fulfill

Promise.resolve(5).then("tiaoguo").then(function(value){
    console.log(value)
})
// 5

2.2.7.4 如果onRejected不是一個(gè)函數(shù)且promise1 rejected,則promise2以同樣的reason reject

Promise.reject(new Error("error")).catch("tiaoguo").catch(function(reason){
    console.log(reason)
})
// Error: error(…)

更多的測(cè)試代碼,大家可以去promises-tests中查看,這是一個(gè)基于規(guī)范的promise測(cè)試庫(kù)。

以上基本是整個(gè)Promise/A+規(guī)范的所有內(nèi)容,如有錯(cuò)誤,歡迎批評(píng)指正。下一篇我會(huì)根據(jù)規(guī)范一步一步實(shí)現(xiàn)一個(gè)Promise polyfill庫(kù)。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/88042.html

相關(guān)文章

  • Promise介紹--Deferred及jQuery

    摘要:我們稱為回調(diào)對(duì)象,它內(nèi)部會(huì)維護(hù)一個(gè)數(shù)組,我們可以向其中添加若干個(gè)回調(diào)函數(shù),然后在某一條件下觸發(fā)執(zhí)行。第一次之后,再次新的回調(diào)函數(shù)時(shí),自動(dòng)執(zhí)行回調(diào)。當(dāng)前面的回調(diào)函數(shù)返回時(shí),終止后面的回調(diào)繼續(xù)執(zhí)行。 最近懶癌發(fā)作,說(shuō)好的系列文章,寫了一半,一直懶得寫,今天補(bǔ)上一篇。 Deferred 我們?cè)谑褂胮romise對(duì)象時(shí),總會(huì)提到一個(gè)與它關(guān)系密切的對(duì)象——Deferred。其實(shí)Deferred沒...

    Darkgel 評(píng)論0 收藏0
  • ES6-7

    摘要:的翻譯文檔由的維護(hù)很多人說(shuō),阮老師已經(jīng)有一本關(guān)于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發(fā)過程中,顯得越來(lái)越重要。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。 JavaScript Promise 迷你書(中文版) 超詳細(xì)介紹promise的gitbook,看完再不會(huì)promise...... 本書的目的是以目前還在制定中的ECMASc...

    mudiyouyou 評(píng)論0 收藏0
  • promise介紹--實(shí)現(xiàn)

    摘要:內(nèi)部總體上分為兩種情況,一種是當(dāng)前對(duì)象狀態(tài)已經(jīng)變?yōu)榛?,此時(shí)則直接把響應(yīng)的回調(diào)函數(shù)添加到異步隊(duì)列中,另一種情況是當(dāng)前對(duì)象狀態(tài)還是,此時(shí)則把響應(yīng)的回調(diào)函數(shù)依次添加到數(shù)組中。 今天,我?guī)е蠹乙徊揭徊礁?guī)范實(shí)現(xiàn)一個(gè)自己的Promise,大家可以對(duì)照我的第二篇文章Promise介紹--規(guī)范篇或官方規(guī)范來(lái)一一學(xué)習(xí)。 Promise內(nèi)部有三個(gè)固定的狀態(tài),我們?cè)谖募刑崆岸x。 const PEN...

    shery 評(píng)論0 收藏0
  • 小而美的Promise庫(kù)——promiz源碼淺析

    摘要:因此,當(dāng)作為參數(shù)的執(zhí)行任意結(jié)果的回調(diào)函數(shù)時(shí),就會(huì)將參數(shù)傳遞給外層的,執(zhí)行對(duì)應(yīng)的回調(diào)函數(shù)。 背景 在上一篇博客[[譯]前端基礎(chǔ)知識(shí)儲(chǔ)備——Promise/A+規(guī)范](https://segmentfault.com/a/11...,我們介紹了Promise/A+規(guī)范的具體條目。在本文中,我們來(lái)選擇了promiz,讓大家來(lái)看下一個(gè)具體的Promise庫(kù)的內(nèi)部代碼是如何運(yùn)作的。 promiz...

    figofuture 評(píng)論0 收藏0
  • Tasks, microtasks, queues and schedules(譯)

    摘要:事件循環(huán)持續(xù)運(yùn)行,直到清空列隊(duì)的任務(wù)。在執(zhí)行期間,瀏覽器可能更新渲染。線索可能會(huì)發(fā)生多次。由于冒泡,函數(shù)再一次執(zhí)行。這意味著隊(duì)列不會(huì)在事件回調(diào)之間處理,而是在它們之后處理。當(dāng)觸發(fā)成功事件時(shí),相關(guān)的對(duì)象在事件之后轉(zhuǎn)為非激活狀態(tài)第四步。 一 前言 一直想對(duì)異步處理做一個(gè)研究,在查閱資料時(shí)發(fā)現(xiàn)了這篇文章,非常深入的解釋了事件循環(huán)中重的任務(wù)隊(duì)列。原文中有代碼執(zhí)行工具,強(qiáng)烈建議自己執(zhí)行一下查看結(jié)...

    tianyu 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<