Open louzhedong opened 4 years ago
Promise是抽象异步处理对象以及对其进行各种操作的组件,本质上其实就是一个状态机,在内部有两个数组分别保存着成功和失败的回调,来实现异步,其实是使用了设计模式中的观察者模式。
通过new Promise实例化的promise对象有以下三个状态
"has-resolution" - Fulfilled
resolve(成功)时。此时会调用onFulfilled
"has-rejection" - Rejected
reject(失败)时。此时会调用onRejected
"unresolved" - Pending
既不是resolve也不是reject的状态。即Promise对象刚被创建后的初始化状态等
当Promise对象的状态从Pending转换为Fulfilled或Rejected之后,这个Promise对象的状态就不会再发生任何变化
一般情况下都使用new Promise来创建对象,但我们也可以使用Promise.resolve(value)的快捷方式。
如Promise.resolve(42)可以看做是以下代码的语法糖
Promise.resolve(42)
new Promise(function(resolve) { resolve(42); })
而且它返回的值也是一个promise对象,可以继续调用then方法
类似Promise.resolve
不仅仅是一个回调函数,它还会将回调函数的返回值进行变换,创建并返回一个Promise对象
使用promise.then(onFulfilled, onRejected)的话
在promise.then(onFulfilled).catch(onRejected)的情况下
只是promise.then(undefined, onRejected)的一个别名
Promise#then和Promise#catch都会返回一个和调用者不同的promise对象
Promise.all接受一个promise对象的数组作为参数,当这个数组里的所有promise对象全部变成resolve或reject状态的时候,它才会去调用.then方法。
传递给Promise.all的promise并不是一个个的顺序执行的,而是同时开始、并行执行的
只要有一个promise对象进入Fulfilled或者Rejected状态的话,就会继续进行后面的处理。在第一个Promise对象变为Fulfilled后,并不会取消其他promise对象的执行
使用Promise.race实现XHR取消
function delayPromise(ms) { return new Promise(function(resolve) { setTimeout(resolve, ms); }); } function timeoutPromise(promise, ms) { var timeout = delayPromise(ms).then(function() { throw new Error("Operation timed out after" + ms + ' ms'); }); return Promise.race([promise, timeout]); } // 示例 function cancelableXHR(URL) { var req = new XMLHttpRequest(); var promise = new Promise(function(resolve, reject) { req.open('GET', URL, true); req.onload = function() { if (req.status = 200) { resolve(req.responseText); } else { reject(new Error(req.statusText)); } }; req.onerror = function(){ reject(new Error(req.statusText)); } req.onabort = function() { reject(new Error('abort this request')); }; req.send(); }); var abort = function() { if (req.readyState !== XMLHttpRequest.UNSENT) { req.abort(); } }; return { promise: promise, abort: abort }; } var object = cancelableXHR('http://xxx/xx'); timeoutPromise(object.promise, 1000).then(function(value) { console.log("taskPromise在规定时间内结束:" + value); }).catch(function(error) { console.log("发生超时", error); })
Promise的状态 Promise必须处于pending,resolved,rejected三个状态之一 当Promise处于pending状态时可以转换到resolved或rejected状态 当Promise处于resolved状态时无法再转换到其他状态,并且有一个无法改变value 当Promise处于rejected状态时无法再转换到其他状态,并且有一个无法改变的reason(reason一般为一个Error对象) Promise的then方法 Promise的then方法接受两个参数 promise.then(onResolved, onRejected); onResolved和onRejected参数都是可选的,如果onResolved或onRejected不是function,则忽略相应的参数。onResolved和onRejected都不能被调用超过一次。 onResolved和onRejected需要通过异步的方式执行,可以用“macro-task”或“micro-task”机制来执行。 同一个Promise的then方法可以被调用多次,当该Promise状态变为resolved或rejected状态时,注册在该Promise上的回调应该根据注册的顺序被调用。 then方法会返回一个Promise promise2 = promise1.then(onResolved, onRejected); 1. 如果`onResolved`或`onRejected`返回一个`x`,那么`promise2`的状态需要根据`x`来决定(至于如何决定`promise2`的状态,会在第三部分中说明)。 2. 如果`onResolved`或`onRejected`抛出一个异常`e`,那么`promise2`必须rejected且`reason = e`。 3. 如果`promise1`是resolved状态且`onResolved`不是一个function那么`promise2`必须resolved,并且`promise2`的value必须与`promise1`相同 4. 如果`promise1`是rejected状态且`onRejected`不是一个function那么`promise2`必须rejected,并且`promise2`的reason必须与`promise1`相同 The Promise Resolution Procedure 这个操作为了兼容不同的PromiseA+标准,具体的步骤如下: 1.如果x和promise是同一个对象的引用(x === promise),那么reject promise并将一个TypeError赋值给reason 2.如果x是一个Promise(x instanceof Promise),那么promise的状态入下: 2.1 如果x处于pending状态那么promise也处于pending状态,直到x状态变为resolved或rejected。 2.2 如果x处于resolved状态,那么用x的value来resolve promise。 2.3 如果x处于rejected状态,那么用x的reason来reject promise 3.如果x是一个对象或function 3.1 如果获取属性x.then的过程中抛出异常e,那么将e作为reason来reject promise 3.2 如果x.then是一个function,那么调用x.then传入参数resolvePromise和rejectPromise 3.2.1 如果resolvePromise被调用且传入的参数为y,那么再次执行此操作,参数为(promise, y) 3.2.2 如果rejectPromise被调用且传入的参数r,那么将r作为reason来reject promise 3.2.3 如果resolvePromise和rejectPromise同时被调用,或者被调用多次,那么优先处理第一次调用,之后的调用都应该被忽略。 3.2.4 如果调用x.then抛出了异常e,若在抛出异常前resolvePromise或rejectPromise已经被调用,那么忽略异常即可。若resolvePromise或rejectPromise没有被调用过,那么将e作为reason来reject promise 3.3 如果x.then不是一个function,那么用x来resolve promise 4.如果x既不是对象也不是function,那么用x来resolve promise
Promise必须处于pending,resolved,rejected三个状态之一
pending
resolved
rejected
value
reason
Promise的then方法接受两个参数
promise.then(onResolved, onRejected);
onResolved和onRejected参数都是可选的,如果onResolved或onRejected不是function,则忽略相应的参数。onResolved和onRejected都不能被调用超过一次。
onResolved
onRejected
onResolved和onRejected需要通过异步的方式执行,可以用“macro-task”或“micro-task”机制来执行。
同一个Promise的then方法可以被调用多次,当该Promise状态变为resolved或rejected状态时,注册在该Promise上的回调应该根据注册的顺序被调用。
then
then方法会返回一个Promise
promise2 = promise1.then(onResolved, onRejected);
1. 如果`onResolved`或`onRejected`返回一个`x`,那么`promise2`的状态需要根据`x`来决定(至于如何决定`promise2`的状态,会在第三部分中说明)。 2. 如果`onResolved`或`onRejected`抛出一个异常`e`,那么`promise2`必须rejected且`reason = e`。 3. 如果`promise1`是resolved状态且`onResolved`不是一个function那么`promise2`必须resolved,并且`promise2`的value必须与`promise1`相同 4. 如果`promise1`是rejected状态且`onRejected`不是一个function那么`promise2`必须rejected,并且`promise2`的reason必须与`promise1`相同
The Promise Resolution Procedure
这个操作为了兼容不同的PromiseA+标准,具体的步骤如下:
x
promise
x === promise
TypeError
x instanceof Promise
x.then
e
resolvePromise
rejectPromise
y
(promise, y)
r
const PENDING = "pending"; const RESOLVED = "resolved"; const REJECTED = "rejected"; function myPromise(fn) { let _this = this; _this.currentState = PENDING; // 初始化状态为pending _this.value = undefined; // 用于保存 then 中的回调,只有当 promise状态为 pending 时才会缓存,并且每个实例至多缓存一个 _this.resolvedCallbacks = []; _this.rejectedCallbacks = []; _this.resolve = function (value) { // 如果value是一个promise,则递归执行 if (value instanceof myPromise) { return value.then(_this.resolve, _this.reject); } setTimeout(() => { if (_this.currentState === PENDING) { _this.currentState = RESOLVED; _this.value = value; _this.resolvedCallbacks.forEach(cb => cb()); } }) }; _this.reject = function (reason) { setTimeout(() => { if (_this.currentState === PENDING) { _this.currentState = REJECTED; _this.value = reason; _this.rejectedCallbacks.forEach(cb => cb()); } }) } try { fn(_this.resolve, _this.reject); } catch (e) { _this.reject(e); } } myPromise.prototype.then = function (onResolved, onRejected) { const self = this; // 规范2.2.7,then必须返回一个新的promise let promise2; // 规范2.2 onResolved 和 onRejected 都为可选参数 onResolved = typeof onResolved === 'function' ? onResolved : v => v; onRejected = typeof onRejected === 'function' ? onRejected : r => { throw r }; if (self.currentState === RESOLVED) { return (promise2 = new myPromise(function (resolve, reject) { // 规范2.2.4保证onFulilled,onReject异步执行,用setTimeout函数 setTimeout(function () { try { const x = onResolved(self.value); resolutionProcedure(promise2, x, resolve, reject); } catch (reason) { reject(reason); } }) })); } if (self.currentState === REJECTED) { return (promise2 = new myPromise(function (resolve, reject) { setTimeout(function () { try { const x = onRejected(self.value); resolutionProcedure(promise2, x, resolve, reject); } catch (reason) { reject(reason); } }) })); } if (self.currentState === PENDING) { return (promise2 = new myPromise(function (resolve, reject) { self.resolvedCallbacks.push(function () { try { const x = onResolved(self.value); resolutionProcedure(promise2, x, resolve, reject); } catch (r) { reject(r); } }) self.rejectedCallbacks.push(function () { try { const x = onRejected(self.value); resolutionProcedure(promise2, x, resolve, reject); } catch (r) { reject(r); } }) })) } } // 规范2.3 function resolutionProcedure(promise2, x, resolve, reject) { // 规范2.3.1,x不能和promise2相同,避免循环引用 if (promise2 === x) { return reject(new TypeError('Error')); } // 规范2.3.2 如果x为Promise,状态为pending需要继续等待,否则执行 if (x instanceof myPromise) { if (x.currentState === PENDING) { x.then(function (value) { resolutionProcedure(promise2, value, resolve, reject); }, reject); } else { x.then(resolve, reject); } return; } // 规范2.3.3.3.3 reject或者resolve其中一个执行过的话,忽略其他 let called = false; // 规范2.3.3 判断x是否为对象或者函数 if (x !== null && (typeof x === 'object' || typeof x === 'function')) { // 规范2.3.3.2,如果不能取出then,就reject try { // 规范2.3.3.1 let then = x.then; if (typeof then === 'function') { // 规范2.3.3.3 then.call(x, y => { if (called) return; called = true; // 规范2.3.3.3.1 resolutionProcedure(promise2, y, resolve, reject); }, e => { if (called) return; called = true; reject(e); }) } else { // 规范2.3.3.4 resolve(x); } } catch (e) { if (called) return; called = true; reject(e); } } else { // 规范2.3.4, x为基本类型 resolve(x); } } myPromise.deferred = function () { const defer = {} defer.promise = new myPromise((resolve, reject) => { defer.resolve = resolve defer.reject = reject }) return defer } try { module.exports = myPromise } catch (e) { }
什么是Promise
Promise是抽象异步处理对象以及对其进行各种操作的组件,本质上其实就是一个状态机,在内部有两个数组分别保存着成功和失败的回调,来实现异步,其实是使用了设计模式中的观察者模式。
通过new Promise实例化的promise对象有以下三个状态
"has-resolution" - Fulfilled
resolve(成功)时。此时会调用onFulfilled
"has-rejection" - Rejected
reject(失败)时。此时会调用onRejected
"unresolved" - Pending
既不是resolve也不是reject的状态。即Promise对象刚被创建后的初始化状态等
当Promise对象的状态从Pending转换为Fulfilled或Rejected之后,这个Promise对象的状态就不会再发生任何变化
Promise的方法
Promise.resolve
一般情况下都使用new Promise来创建对象,但我们也可以使用Promise.resolve(value)的快捷方式。
如
Promise.resolve(42)
可以看做是以下代码的语法糖而且它返回的值也是一个promise对象,可以继续调用then方法
Promise.reject
类似Promise.resolve
Promise#then
不仅仅是一个回调函数,它还会将回调函数的返回值进行变换,创建并返回一个Promise对象
使用promise.then(onFulfilled, onRejected)的话
在promise.then(onFulfilled).catch(onRejected)的情况下
Promise#catch
只是promise.then(undefined, onRejected)的一个别名
Promise#then和Promise#catch都会返回一个和调用者不同的promise对象
Promise.all
Promise.all接受一个promise对象的数组作为参数,当这个数组里的所有promise对象全部变成resolve或reject状态的时候,它才会去调用.then方法。
传递给Promise.all的promise并不是一个个的顺序执行的,而是同时开始、并行执行的
Promise.race
只要有一个promise对象进入Fulfilled或者Rejected状态的话,就会继续进行后面的处理。在第一个Promise对象变为Fulfilled后,并不会取消其他promise对象的执行
Promise/A+规范
Promise实现