本篇文章是Promise
系列文章的第二篇,主要是讲解基于Promise/A+
规范,在传入不一样类型的参数时,promise
内部分别会如何处理。本章的主要目的是让你们对promise
有一个更加深刻的理解,也为下一篇讲如何实现一个promise
库作准备。(写完以后以为好水。。。)git
英文版本的规范见这里,segmentfault上也有人把规范翻译为中文,见这里。github
在此,我主要是经过使用例子,讲解一下规范中then
方法和Promise Resolution Procedure
的每一种状况。web
规范中对于构造函数没有明确说明,因此在此处拿出来说解一下。segmentfault
和普通JavaScript对象同样,咱们一样是经过new关键词来建立一个Promise
对象实例。构造函数只接收一个参数,且该参数必须是一个函数,任何其余的值好比undefined
、null
、5
、true
等都会报一个TypeError
的错误。例:promise
new Promise(true) // Uncaught TypeError: Promise resolver true is not a function(…)
一样,若是你没有经过new关键词建立,而是直接执行Promise(),一样也会报一个TypeError
的错误。session
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有三种状态,pending
、fulfilled
、rejected
,实例刚建立时处于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
。以下:oop
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
是个什么东西呢?它是根据什么变为fulfilled
或rejected
的呢?这就是咱们接下来要讲解的Promise Resolution Procedure
,我把它称做“Promise处理程序”。测试
讲以前,咱们先说几个promise
规范中的几个术语。
promise 它是一个拥有then
方法的对象或函数,且符合该规范
thenable 拥有then
方法的对象或函数
value 是指一个合法的 Javascript
值
exception throw
语句抛出的异常
reason 描述promise为何失败的值
Promise Resolution Procedure
是对传入的promise和value进行抽象操做。咱们可一个把它理解成resolve(promise, value)
,对参数promise和value进行一系列处理操做。下面咱们按照规范中的顺序,依次介绍每种状况。
2.3.1 若是promise
和value
指向同一个对象,则reject
该promise
并以一个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 #<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
来调用,则传入r
来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 若是resolvePromise
和rejectPromise
都被调用,或其中一个被调用了屡次,则以第一次调用的为准,并忽略以后的调用。例:
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 若是resolvePromise
或rejectPromise
已经调用,则忽略它,例:
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
来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
不是一个函数,则传入value
来fulfill
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 onFulfilled
和onRejected
都是可选的
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
以后调用,且把promise
的value
做为它的第一个参数
这个从咱们全部的例子中均可以看出
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
以后调用,且把promise
的reason
做为它的第一个参数
2.2.3.2 它不能够在promise
变为rejected
以前调用
2.2.3.3 它只能够被调用一次
onRejected
和onFulfilled
基本相似,这里再也不次赘述
2.2.4 onFulfilled
和onRejected
是在执行环境中仅包含平台代码时调用
这里有一个备注,平台代码是指引擎、执行环境、以及promise
的实现代码。实际过程当中,要确保onFulfilled
和onRejected
是异步执行的,它是在event loop
过程当中then
方法被调用以后的新调用栈中执行。咱们可使用setTimeout
或setImmediate
等macro-task
机制来实现,也可使用MutationObserver
或process.nextTick
等micro-task
机制来实现。promise
的实现自己就被看做是平台代码,它自己就包含一个处理器能够调用的任务调度队列。
才疏学浅,没理解它这一条到底要表达一个什么意思。。。应该指的就是异步执行,由于异步执行的时候,页面中同步的逻辑都已经执行完毕,因此只剩下平台代码。
注:原生的Promise
实现属于micro-task
机制。macro-task
和micro-task
分别是两种异步任务,它们的不一样后面会单独讲一下。下面列出了常见的异步方法都属于那种异步机制:
macro-task: script(总体代码), setTimeout, setInterval, setImmediate, I/O, UI rendering
micro-task: process.nextTick, 原生Promise, Object.observe, MutationObserver
2.2.5 onFulfilled
和onRejected
必须做为函数来调用,没有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 若是onFulfilled
或onRejected
返回了一个值x
,则执行resolve(promise2, x)
Promise.resolve(5).then(function(value){ return ++value }).then(function(value){ console.log(value) }) // 6
2.2.7.2 若是onFulfilled
或onRejected
抛出了异常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
库。