导航


HTML

CSS

JavaScript

浏览器 & 网络

版本管理

框架

构建工具

TypeScript

性能优化

软实力

算法

UI、组件库

Node

冷门技能

针对性攻坚(TODO)


是什么

异步编程的一种解决方案

Promise 状态

var promise = new Promise(function(resolve, reject) {
  setTimeout(function() {
  	Math.random() * 100 > 60 ? resolve('ok') : reject('no')
  })
})
promise.then(val => {
	console.log(val);
}, reason => {
	console.log(reason);
})

Promise 特性

then 的返回值作为下一次 then 的执行参数

var promise = new Promise(function(resolve, reject){
  setTimeout(function(){
  	Math.random() * 100 > 60 ? resolve('ok') : reject('no')
  })
})
promise.then(val => {
	console.log(val);
  return 1
}, reason => {
	console.log(reason);
  return 2
}).then(val => {
	console.log('then2-', val);
}, reason => {
	console.log('then2-', reason);
})

Untitled

var promise = new Promise(function(resolve, reject) {
  setInterval(function() {
  	Math.random() * 100 > 60 ? resolve('ok') : reject('no')
  })
})
promise.then(val => {
	console.log(val);
  return new Promise((resolve, reject) => {
  	resolve('new promise')
  })
}, reason => {
	console.log(reason);
  return 2
}).then(val => {
	console.log('then2-', val);
}, reason => {
	console.log('then2-', reason);
})

Untitled

resolve 导致抛出错误会被 reject 接收

var promise = new Promise((resolve, reject) => {
	resolve(a);
})

promise.then((val) => {
	console.log('resolve', val);
}, (reason) => {
	console.log('reject', reason);
})

Untitled

catch 等同于:then 第一个参数为 null ,第二个参数为 reject 的回调函数

var promise = new Promise((resolve, reject) => {
	resolve(a);
})

promise.then(null, (reason) => {
	console.log('reject', reason);
})

promise.catch((reason) => {
	console.log('reject', reason);
})

Untitled

pormise 状态一旦固化,就无法再改变

var promise = new Promise((resolve, reject) => {
	resolve('ok');
  console.log(a); // 这个报错因为状态固化,无法被捕获
})

promise.then((val) => {
	console.log('res', val);
}).catch((reason) => {
	console.log('reject', reason);
})

Untitled

catch 冒泡(可以捕获多层then的异常),then() 不传参数会被直接忽略

var promise = new Promise((resolve, reject) => {
  resolve(1);
});

promise
  .then((val) => {
    console.log("res", val);
    throw new Error("then error");
  })
  .then()
  .then()
  .catch((reason) => {
    console.log("reject", reason);
  });

Untitled

⭐️ 值穿透

值穿透指的是,链式调用的参数不是函数时,会发生值穿透,就传入的非函数值忽略,传入的是之前的函数参数。

Promise.resolve(1)
    .then(2)
    .then(Promise.resolve(3))
    .then(console.log)

// 答案:

// 传入2或者promise的fulfilled状态都会发生值穿透。
// 打印 1

Untitled

Promise.resolve(1)
  .then(2)
  .then(Promise.reject(3))
  .then(
    console.log
  , console.log
  );

// 答案:

// 打印 1 然后报错
Promise {<fulfilled>: undefined}
VM384:3 Uncaught (in promise) 3

Untitled

Promise.resolve(1)
    .then(() => { return 2 })
    .then(() => { return 3 })
    .then(console.log)

// 答案

// 3
Promise.resolve(1)
    .then(function () {
        return 2
    })
    .then(() => { Promise.resolve(3) })
    .then(console.log)
// 答案

// undefined

⭐️ 异常穿透(then 中捕获到异常后不会传递给后续 catch)

let promise = new Promise((resolve, reject) => {
	resolve('First resolve');
});

promise.then(value => {
	return value;
})
.then((value) => {
	return new Promise((resolve, reject) => {
  	setTimeout(() => {
    	reject('ERROR');
    }, 2000);
  });
})
.then(value => {
	console.log(value);
}, reason => {
	console.log('Rejected: ' + reason); // Rejected: ERROR
})
.then(value => {
  throw new Error('Throw Error');
})
.then(value => {
  console.log(value);
}, reason => {
	console.log('Then: ' + reason); // Then: Error: Throw Error
})
.catch(err => {
	console.log('Catch: ' + err);
});

Untitled

Promise.reject(1)
    .then(res => {
        console.log(res);
    })
    .then(res => { console.log(res) },
        rej => {
            console.log(`rej****${rej}`);
        })
    .catch(err => {
        console.log(`err****${err}`);
    })

// 答案:

// rej****1
Promise.reject(1)
    .then(res => {
        console.log(res);
    })
    .then(res => { console.log(res) },
        rej => {
            console.log(`rej****${rej}`);
        })
    .then(res => {
        console.log(`res****${res}`);
    }, rej => {
        console.log(`rej****${rej}`);
    })
    .catch(err => {
        console.log(`err${err}`);
    })

// 答案:

// rej****1
// res****undefined

catch 之后还可以继续 then

let promise = new Promise((resolve, reject) => {
	resolve('First resolve');
});

promise.then(value => {
	return value;
})
.then((value) => {
	return new Promise((resolve, reject) => {
  	setTimeout(() => {
    	reject('ERROR');
    }, 2000);
  });
})
.then(value => {
	console.log(value);
}, reason => {
	console.log('Rejected: ' + reason); // Rejected: ERROR
})
.then(value => {
  throw new Error('Throw Error');
})
.then(value => {
  console.log(value);
})
.catch(err => {
	console.log('Catch: ' + err); // Catch: Error: Throw Error
  return 'Catch Error';
})
.then(value => {
	console.log('Then: ' + value); // Then: Catch Error
});

Untitled

p2 依赖于 p1 的状态,会导致 p2 的状态无效,会等待 p1 的状态

var p1 = new Promise((resolve, reject) => {
	setTimeout(function(){
  	reject(new Error('fail'));
  }, 3000);
})

var p2 = new Promise((resolve, reject) => {
	setTimeout(function(){
  	resolve(p1);
  }, 1000);
})

p2.then(res => console.log('res', res))
	.catch(err => console.log('p2-err-', err))

Untitled

reject 不会等待参数类型是 promise 的结果

const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve(1);
  }, 1000);
});
const p2 = new Promise((resolve, reject) => {
  reject(p1);
});
p2.then(value => {
  console.log('value', value);
}, err => {
  console.log('err', err);
  err.then(val => console.log(val), err => console.log(err));
});

Untitled

状态固化后面的代码依然会执行,但是 resolve、reject 后面的错误无法被捕获

var p1 = new Promise((resolve, reject) => {
	resolve(1);
  console.log(a) // resolve 后的错误不会被捕获
})

p1.then(res => console.log(res))
	.catch(err => console.log('p1-err-', err))

console.log(3);

Untitled

但如果 resolve、reject 之后的代码不报错,还是会正常执行:

var p1 = new Promise((resolve, reject) => {
	resolve(1);
  console.log(233)
})

p1.then(res => console.log(res))
	.catch(err => console.log('p1-err-', err))

console.log(3);

Untitled

var p1 = new Promise((resolve, reject) => {
	reject(new Error());
  console.log(2)
})

p1.then(res => console.log(res))
	.catch(err => console.log('p1-err-', err))

console.log(3);

Untitled

var p1 = new Promise((resolve, reject) => {
	reject(new Error());
  console.log(a); // reject后的错误不会被捕获
})

p1.then(res => console.log(res))
	.catch(err => console.log('p1-err-', err))

console.log(3);

Untitled

Promise 方法

Promise.all()

处理多个 promise

const fs = require('fs');
var p1 = new Promise((resolve, reject) => {
	fs.readFile('./name.txt', 'utf-8', function(err, data){
  	if(err){
    	console.log(err);
    }
    resolve(data);
  })
})
var p2 = new Promise((resolve, reject) => {
	fs.readFile('./number.txt', 'utf-8', function(err, data){
  	if(err){
    	console.log(err);
    }
    resolve(data);
  })
})
var p3 = new Promise((resolve, reject) => {
	fs.readFile('./score.txt', 'utf-8', function(err, data){
  	if(err){
    	console.log(err);
    }
    resolve(data);
  })
})
var p = Promise.all([p1, p2, p3]);

成功会返回新的 promise 对象数组

var p1 = new Promise((resolve, reject) => {
	setTimeout(function(){
		resolve('p1: 1000')  
  }, 1000)
})
var p2 = new Promise((resolve, reject) => {
	setTimeout(function(){
		resolve('p2: 2000')  
  }, 2000)
})
var p3 = new Promise((resolve, reject) => {
	setTimeout(function(){
		resolve('p3: 3000')  
  }, 3000)
})
var p = Promise.all([p1, p2, p3]);
p.then(res => console.log('res', res))
	.catch(err => console.log('err', err))

Untitled

有一个失败就返回第一个失败的返回值

var p1 = new Promise((resolve, reject) => {
	setTimeout(function(){
		reject('p1: 1000')  
  }, 1000)
})
var p2 = new Promise((resolve, reject) => {
	setTimeout(function(){
		reject('p2: 2000')  
  }, 2000)
})
var p3 = new Promise((resolve, reject) => {
	setTimeout(function(){
		reject('p3: 3000')  
  }, 3000)
})
var p = Promise.all([p1, p2, p3]);
p.then(res => console.log('res', res))
	.catch(err => console.log('err', err))

Untitled

var p1 = new Promise((resolve, reject) => {
	setTimeout(function(){
		resolve('p1: 1000')  
  }, 1000)
})
var p2 = new Promise((resolve, reject) => {
	setTimeout(function(){
		reject('p2: 2000')  
  }, 2000)
})
var p3 = new Promise((resolve, reject) => {
	setTimeout(function(){
		reject('p3: 3000')  
  }, 3000)
})
var p = Promise.all([p1, p2, p3]);
p.then(res => console.log('res', res))
	.catch(err => console.log('err', err))

Untitled

Promise.race()

任意一个 promise 失败或者成功, 就会返回第一个固化的 promise 的结果

var p1 = new Promise((resolve, reject) => {
	setTimeout(function(){
		resolve('p1: 1000')  
  }, 1000)
})
var p2 = new Promise((resolve, reject) => {
	setTimeout(function(){
		reject('p2: 2000')  
  }, 2000)
})
var p = Promise.race([p1, p2]);
p.then(res => console.log('res', res))
	.catch(err => console.log('err', err))

Untitled

var p1 = new Promise((resolve, reject) => {
	setTimeout(function(){
		reject('p1: 1000')  
  }, 1000)
})
var p2 = new Promise((resolve, reject) => {
	setTimeout(function(){
		reject('p2: 2000')  
  }, 2000)
})
var p = Promise.race([p1, p2]);
p.then(res => console.log('res', res))
	.catch(err => console.log('err', err))

Untitled

Promise.resolve()

thenable 能把对象转为 promise

var thenable = {
	then: function (resolve, reject) {
  	resolve(1);
  }
}
var p = Promise.resolve(thenable)
p.then(function(value) {
	console.log(value)
})

Untitled

setTimeout(function() {
	console.log(2);
})

Promise.resolve().then(function() {
	console.log(1);
})
console.log(3);

Untitled

Promise.any()

E12 新增的 Promise 的方法

// 当有成功的时候,返回最快那个成功
function fn(time, isResolve) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      isResolve ? resolve(`${time}毫秒后我成功啦!!!`) : reject(`${time}毫秒后我失败啦!!!`)
    }, time)
  })
}

Promise.any([fn(2000, true), fn(3000), fn(1000, true)]).then(res => {
  console.log(res) // 1秒后 输出  1000毫秒后我成功啦
}, err => {
  console.log(err)
})

// 当全都失败时
function fn(time, isResolve) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      isResolve ? resolve(`${time}毫秒后我成功啦!!!`) : reject(`${time}毫秒后我失败啦!!!`)
    }, time)
  })
}

Promise.any([fn(2000), fn(3000), fn(1000)]).then(res => {
  console.log(res)
}, err => {
  console.log(err) // 3秒后 报错 all Error
})

⭐️ 手写 Promise

Promise 原理

Promise 的核心是基于 发布订阅模式事件队列 实现的。

核心要点:

  1. Promise 是一个对象,它持有一个异步操作的结果。
  2. 它有 then、catch 和 finally 方法,分别用于处理成功、失败和无论结果如何都执行的逻辑。
  3. 状态一旦改变,就无法再改变
  4. 异步操作结果是通过微任务(Microtask)队列来处理的。

核心思路

  1. Promise 有三个状态:Pending、Fulfilled、Rejected。
  2. resolve 和 reject 方法用于改变状态,并传递值。
  3. 状态一旦改变,不可逆。
  4. then 方法会将回调存储起来,状态改变时调用对应的回调。

简易版