promise解决的问题
- 回调地狱
- 处理多个异步请求
普通逻辑
/**
* 手写一个promise
* promise的本质是一个状态机
* 主要有三个状态pending,fulfilled,rejected
* 且只有pending可以变成fulfilled、rejected
*/
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
// 为什么使用数组,因为对象创建后,可以使用多次then方法
// const promise = new Promise();
// promise.then();
// promise.then();
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
//避免在executor里同时resolve、reject
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 依次将对应的函数执行
this.onResolvedCallbacks.forEach(fn=>fn());
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// 依次将对应的函数执行
this.onRejectedCallbacks.forEach(fn=>fn());
}
}
// 立即执行
try{
executor(resolve,reject);
}catch (e){
reject(e);
}
}
then(onFulfilled,onRejected) {
// 避免异步executor
if (this.status === PENDING){
// 将方法先放入回调数组中 等异步完成在调用
this.onResolvedCallbacks.push(()=>{
onFulfilled(this.value)
})
// 将方法先放入回调数组中 等异步完成在调用
this.onRejectedCallbacks.push(()=>{
onRejected(this.value)
})
}
if (this.status === FULFILLED){
onFulfilled(this.value)
}
if (this.status === REJECTED){
onRejected(this.reason)
}
}
}
增加then 的链式调用 和 值穿透
/**
* promise.js
* 手写一个promise
* promise的本质是一个状态机
* 主要有三个状态pending,fulfilled,rejected
* 且只有pending可以变成fulfilled、rejected
*/
const PENDING = 'PENDING';
const FULFILLED = 'FULFILLED';
const REJECTED = 'REJECTED';
const resolvePromise = (promise, x, resolve, reject) => {
if (promise === x) {
return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
let called = false;
if ((typeof x === 'object' && x != null) || typeof x === 'function') {
try {
let then = x.then;
if (typeof then === 'function') {
// 不要写成 x.then,直接 then.call 就可以了 因为 x.then 会再次取值,Object.defineProperty Promise/A+ 2.3.3.3
// 看注释1
then.call(x, y => {
if (called) return;
called = true;
// 递归解析的过程(因为可能 promise 中还有 promise) Promise/A+ 2.3.3.3.1
resolvePromise(promise, y, resolve, reject);
}, r => {
if (called) return;
called = true;
reject(r);
})
} else {
// 2.3.3.4 If then is not a function, fulfill promise with x
resolve(x);
}
} catch (e) {
// Promise/A+ 2.3.3.2
if (called) return;
called = true;
reject(e)
}
} else {
// 如果 x 是个普通值就直接返回 resolve 作为结果 Promise/A+ 2.3.4
resolve(x)
}
}
class Promise {
constructor(executor) {
this.status = PENDING;
this.value = undefined;
this.reason = undefined;
// 为什么使用数组,因为对象创建后,可以使用多次then方法
// const promise = new Promise();
// promise.then();
// promise.then();
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
//避免在executor里同时resolve、reject
if (this.status === PENDING) {
this.status = FULFILLED;
this.value = value;
// 依次将对应的函数执行
this.onResolvedCallbacks.forEach(fn => fn());
}
}
const reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED;
this.reason = reason;
// 依次将对应的函数执行
this.onRejectedCallbacks.forEach(fn => fn());
}
}
// 立即执行
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
then(onFulfilled, onRejected) {
// Promise/A+ 允许then方法什么都不传,所以需要默认方法将值往后面的then传
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : v => v;
onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
// 每次调用 then 都返回一个新的 promise Promise/A+ 2.2.7
const promise = new Promise((resolve, reject) => {
if (this.status === PENDING) {
this.onResolvedCallbacks.push(() => {
// 2.2.7.2 如果onFulfilled 或者 onRejected异常需要reject
setTimeout(()=>{
try {
const x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
},0)
})
this.onRejectedCallbacks.push(() => {
// 2.2.7.2 如果onFulfilled 或者 onRejected异常需要reject
setTimeout(()=>{
try {
const x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
})
})
}
if (this.status === FULFILLED) {
setTimeout(()=>{
try {
const x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
})
}
if (this.status === REJECTED) {
setTimeout(()=>{
try {
const x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch (e) {
reject(e);
}
})
}
});
return promise;
}
}
// 增加defer与deferred使得可以测试
Promise.defer = Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
})
return dfd;
}
// 必须导出、和defer与deferred两个方法不然会报错
// Promise没有defer或者deferred会报错 adapter.deferred is not a function
module.exports = Promise
测试方法
npm install -g promises-aplus-tests
promises-aplus-tests promise/index.js
注释1
如果不使用call会产生副作用,比如
var b= 0;
var a = {
get then(){
b++;
return function(){
console.log(a);
}
}
};
var hello2 = a.then; // 调用1次
a.then(); // 调用2次
console.log(b); // 2
var b= 0;
var a = {
get then(){
b++;
return function(){
console.log(a);
}
}
};
var hello2 = a.then; // 调用1次
hello2.call(a); // 不会调用
console.log(b); // 1
参考链接
为什么promise需要异步?
因为需要保证代码的一致性
promise.then(function(){
if (trueOrFalse) {
// 同步执行
foo();
} else {
// 异步执行 (如:使用第三方库)
setTimeout(function(){
foo();
})
}
});
bar();
假如是同步代码那么就会受到影响