国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Promise介紹--規范篇

tylin / 692人閱讀

摘要:規范中對于構造函數沒有明確說明,所以在此處拿出來講解一下。構造函數只接收一個參數,且該參數必須是一個函數,任何其他的值比如等都會報一個的錯誤。

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

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

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

constructor

規范中對于構造函數沒有明確說明,所以在此處拿出來講解一下。

和普通JavaScript對象一樣,我們同樣是通過new關鍵詞來創建一個Promise對象實例。構造函數只接收一個參數,且該參數必須是一個函數,任何其他的值比如undefinednull5true等都會報一個TypeError的錯誤。例:

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

同樣,如果你沒有通過new關鍵詞創建,而是直接執行Promise(),同樣也會報一個TypeError的錯誤。

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

所以,我們必須通過new Promise(function()=>{})的方式來創建一個Promise實例。通常我們見到的創建一個Promise實例的代碼如下:

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

這才是正確的姿勢~ 從該例子中,我們可以看到創建Promise實例時傳入的函數,同時還接受兩個參數,它們分別對應Promise內部實現的兩個方法。上一篇文章中,我提到過Promise有三種狀態,pendingfulfilledrejected,實例剛創建時處于pending狀態,當執行reject方法時,變為rejected狀態,如下所示:

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}

而當執行resolve方法時,它可能變為fulfilled,也有可能變為rejected狀態。也就是說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是個什么東西呢?它是根據什么變為fulfilledrejected的呢?這就是我們接下來要講解的Promise Resolution Procedure,我把它稱作“Promise處理程序”。

Promise Resolution Procedure

講之前,我們先說幾個promise規范中的幾個術語。

promise 它是一個擁有then方法的對象或函數,且符合該規范
thenable 擁有then方法的對象或函數
value 是指一個合法的 Javascript
exception throw語句拋出的異常
reason 描述promise為什么失敗的值

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

2.3.1 如果promisevalue指向同一個對象,則rejectpromise并以一個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函數保存在defer中,這樣就可以在外部對promise進行狀態改變,defer.resolve(promise)中的promise正是我們創建的對象,根據規范拋出了TypeError

2.3.2 如果value是一個promise對象,且是基于當前實現創建的。

2.3.2.1 如果value處于pending狀態,則promise同樣pending并直到value狀態改變。
2.3.2.2 如果value處于fulfilled狀態,則使用相同的value值fulfill promise
2.3.2.3 如果value處于rejected狀態,則使用相同的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狀態時,它依然處于pending狀態,當3秒后promise1變為fulfilled后,promise隨即變為fulfilled并以5作為value傳給then添加的成功回調函數中。

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(…)

失敗時例子與成功時類似。

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

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

上例中獲取value.then時,會拋出異常

2.3.3.3 如果then是一個函數,則把value作為函數中this指向來調用它,第一個參數是resolvePromise,第二個參數是rejectPromise

其實這里主要是為了兼容兩種情況,第一種是傳入的value是個Deferred對象,則狀態和Deferred對象一致;另一種情況是不是使用當前構造函數創建的Promise對象,通過這種方式可以兼容,達到一致的效果。

2.3.3.3.1 如果resolvePromise通過傳入y來調用,則執行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來調用,則傳入rreject 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都被調用,或其中一個被調用了多次,則以第一次調用的為準,并忽略之后的調用。例:

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 如果調用then拋出異常e:

2.3.3.3.4.1 如果resolvePromiserejectPromise已經調用,則忽略它,例:

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 否則,則傳入ereject 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不是一個函數,則傳入valuefulfill promise,例:

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

一個promise必須提供一個then方法來處理成功或失敗。

then方法接收兩個參數:

promise.then(onFulfilled, onRejected)

2.2.1 onFulfilledonRejected都是可選的
2.2.1.1 如果onFulfilled不是一個函數,則忽略。例:

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

2.2.1.2 如果onRejected不是一個函數,則忽略。例:

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

// Error: error(…)

2.2.2 如果onFulfilled是一個函數
2.2.2.1 它必須在promise變為fulfilled之后調用,且把promisevalue作為它的第一個參數

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

2.2.2.2 它不可以在promise變為fulfilled之前調用

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執行的時間可以看出promise直到變為fulfilled后才調用

2.2.2.3 它只可以被調用一次

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

2.2.3 如果onRejected是一個函數
2.2.3.1 它必須在promise變為rejected之后調用,且把promisereason作為它的第一個參數
2.2.3.2 它不可以在promise變為rejected之前調用
2.2.3.3 它只可以被調用一次

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

2.2.4 onFulfilledonRejected是在執行環境中僅包含平臺代碼時調用

這里有一個備注,平臺代碼是指引擎、執行環境、以及promise的實現代碼。實際過程中,要確保onFulfilledonRejected是異步執行的,它是在event loop過程中then方法被調用之后的新調用棧中執行。我們可以使用setTimeoutsetImmediatemacro-task機制來實現,也可以使用MutationObserverprocess.nextTickmicro-task機制來實現。promise的實現本身就被看作是平臺代碼,它本身就包含一個處理器可以調用的任務調度隊列。

才疏學淺,沒理解它這一條到底要表達一個什么意思。。。應該指的就是異步執行,因為異步執行的時候,頁面中同步的邏輯都已經執行完畢,所以只剩下平臺代碼。

注:原生的Promise實現屬于micro-task機制。macro-taskmicro-task分別是兩種異步任務,它們的不同后面會多帶帶講一下。下面列出了常見的異步方法都屬于那種異步機制:

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

2.2.5 onFulfilledonRejected必須作為函數來調用,沒有this

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

2.2.6 同一個promise上的then方法可能會調用多次
2.2.6.1 如果promise fulfilled,則所有的onFulfilled回調函數按照它們添加的順序依次調用。

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回調函數按照它們添加的順序依次調用。

例子與上例類似

2.2.7 then方法會返回一個全新的promise

promise2 = promise1.then(onFulfilled, onRejected);

2.2.7.1 如果onFulfilledonRejected返回了一個值x,則執行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不是一個函數且promise1 fulfilled,則promise2以同樣的value fulfill

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

2.2.7.4 如果onRejected不是一個函數且promise1 rejected,則promise2以同樣的reason reject

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

更多的測試代碼,大家可以去promises-tests中查看,這是一個基于規范的promise測試庫。

以上基本是整個Promise/A+規范的所有內容,如有錯誤,歡迎批評指正。下一篇我會根據規范一步一步實現一個Promise polyfill庫。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88042.html

相關文章

  • Promise介紹--Deferred及jQuery

    摘要:我們稱為回調對象,它內部會維護一個數組,我們可以向其中添加若干個回調函數,然后在某一條件下觸發執行。第一次之后,再次新的回調函數時,自動執行回調。當前面的回調函數返回時,終止后面的回調繼續執行。 最近懶癌發作,說好的系列文章,寫了一半,一直懶得寫,今天補上一篇。 Deferred 我們在使用promise對象時,總會提到一個與它關系密切的對象——Deferred。其實Deferred沒...

    Darkgel 評論0 收藏0
  • ES6-7

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

    mudiyouyou 評論0 收藏0
  • promise介紹--實現

    摘要:內部總體上分為兩種情況,一種是當前對象狀態已經變為或,此時則直接把響應的回調函數添加到異步隊列中,另一種情況是當前對象狀態還是,此時則把響應的回調函數依次添加到數組中。 今天,我帶著大家一步一步跟著規范實現一個自己的Promise,大家可以對照我的第二篇文章Promise介紹--規范篇或官方規范來一一學習。 Promise內部有三個固定的狀態,我們在文件中提前定義。 const PEN...

    shery 評論0 收藏0
  • 小而美的Promise庫——promiz源碼淺析

    摘要:因此,當作為參數的執行任意結果的回調函數時,就會將參數傳遞給外層的,執行對應的回調函數。 背景 在上一篇博客[[譯]前端基礎知識儲備——Promise/A+規范](https://segmentfault.com/a/11...,我們介紹了Promise/A+規范的具體條目。在本文中,我們來選擇了promiz,讓大家來看下一個具體的Promise庫的內部代碼是如何運作的。 promiz...

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

    摘要:事件循環持續運行,直到清空列隊的任務。在執行期間,瀏覽器可能更新渲染。線索可能會發生多次。由于冒泡,函數再一次執行。這意味著隊列不會在事件回調之間處理,而是在它們之后處理。當觸發成功事件時,相關的對象在事件之后轉為非激活狀態第四步。 一 前言 一直想對異步處理做一個研究,在查閱資料時發現了這篇文章,非常深入的解釋了事件循環中重的任務隊列。原文中有代碼執行工具,強烈建議自己執行一下查看結...

    tianyu 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<