Promise
- 优势:使用链式调用解决回调过程中的问题
- 基本用法
const promise = new Promise(function(resolve, reject) {
resolve(100);
reject(new Error('promise reject'))
})
promise.then(function(value){
console.log(value)
},function(err){
console.log(err)
})
// 使用案例
function ajax (url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open('GET', url)
xhr.responseType = 'json';
xhr.onload = function () {
if(this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.responseText));
}
}
xhr.send()
})
}
ajax('/api/foo.json').then(function (response) {
console.log(response)
},function (err) {
console.log(err)
})
- 链式调用
- 可以避免回调嵌套
- Promise 对象的then 方法会返回一个全新的 Promise 对象
- 后面的then方法就是在为上一个then返回的 Promise 注册回调
- 并行请求
- all:等待所有任务结束后结束
ajax('api/urls.json')
.then(value => {
const urls = Object.values(value);
const tasks = urls.map(url => ajax(url));
return Promise.all(tasks)
})
.then(value => {
console.log(value);
})
- race:以第一个结束的promise为准
const request = ajax('/api/posts.json')
const timeout = new Promise((resolve, reject) => {
setTimeout(() => reject(new Error('timeout')), 500)
})
Promise.race([
request,
timeout,
])
.then(value => {
console.log(value)
})
.catch(err => {
console.log(err)
})
- 如果一个报错,其他会执行吗:
- 实例化的时候就已经执行了
Generator
生成器是一种返回迭代器的函数,通过function关键字后的星号(*)来表示,函数中会用到新的关键字yield。星号可以紧挨着function关键字,也可以在中间添加一个空格.Generator 函数只要传入co函数,就会自动执行。
-
每当执行完一条yield语句后函数就会自动停止执行, 直到再次调用next();
-
yield关键字只可在生成器内部使用,在其他地方使用会导致程序抛出错误;
-
可以通过函数表达式来创建生成器, 但是不能使用箭头函数
let generator = function *(){}
- 基本用法
function * foo(){
console.log('start');
try{
const res = yield 'foo'
console.log(res) // bar
}catch(e){
console.log(e) // err
}
}
const generator = foo();
const result = generator.next();
console.log(result) // { value: 'foo', done: false }
generator.next('bar');
generator.throw(new Error('err'))
- 异步方案
function * main(){
try{
const users = yield ajax('...')
console.log(users)
const posts = yield ajax('...')
console.log(posts)
}catch(e){
console.log(e)
}
}
function co (generator){
const g = generator()
function handleResult(result){
if(result.done) return
result.value.then(data=>{
handleResult(g.next(data))
}, err => {
g.throw(err)
})
}
handleResult(g.next())
}
co(main)
- Promise 解决回调呀地狱的最大问题是代码冗余,原来的任务被 Promise 包装了一下,不管什么操作,一眼看去都是一堆then,原来的语义变得很不清楚。generator的语法解决了这个问题。
Async
- 优势: 它是 Generator 函数的语法糖。而async函数自带执行器,不需要调用next方法,或者用co模块,就能真正执行; async函数的await命令就是Promise内部then命令的语法糖。
async function main(){
try{
const users = await ajax('...')
console.log(users)
const posts = await ajax('...')
console.log(posts)
}catch(e){
console.log(e)
}
}
const promise = main()
promise.then(()=>{
console.log('completed')
})
- 利用Async封装一个函数, 能够让generator自动执行到完毕
function longTimeFn(time) {
return new Promise(resolve => {
setTimeout(() => {
resolve(time);
}, time);
})
};
function asyncFunc(generator) {
const iterator = generator(); // 接下来要执行next
// data为第一次执行之后的返回结果,用于传给第二次执行
const next = (data) => {
const {
value,
done
} = iterator.next(data); // 第二次执行,并接收第一次的请求结果 value 和 done
if (done) return; // 执行完毕, 直接返回
// 第一次执行next时,yield返回的 promise实例 赋值给了 value
value.then(data => {
next(data); // 当第一次value 执行完毕且成功时,执行下一步(并把第一次的结果传递下一步)
});
}
next();
};
asyncFunc(function* () {
let data = yield longTimeFn(1000);
console.log(data);
data = yield longTimeFn(2000);
console.log(data);
return data;
})
Promise原理
// 1.Promise 中有三种状态分别为 成功 fulfilled 失败 rejected 等待 pending;pending -> fulfilled pending -> rejecte d一旦状态确定就不可更改
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
// 2.Promise就是一个类,在执行这个类的时候需要传递一个执行器进去执行
class MyPromise {
constructor(expector){
try{
expector(this.resolve, this.reject)
}catch(e){
this.reject(e)
}
}
status = PENDING;
value = undefined;
reason = undefined;
successCallback = [];
errorCallback = [];
// 3.resolve和reject函数是用来更改状态的:resolve: fulfilled reject: rejected
resolve = value=>{
if(this.status !== PENDING) return;
this.status = FULFILLED;
this.value = value;
while(this.successCallback.length) this.successCallback.shift()();
}
reject = reason =>{
if(this.status !== PENDING) return;
this.status = REJECTED;
this.reason = reason;
while(this.errorCallback.length) this.errorCallback.shift()();
}
// 4.then方法内部做的事情就判断状态,如果状态是成功 调用成功的回调函数,失败则调用失败函数;then成功回调有一个参数表示成功之后的值,then失败回调有一个参数表示失败原因
then(successCallback, errorCallback){
// 9. 处理空参数
successCallback = successCallback ? successCallback : value => value;
errorCallback = errorCallback ? errorCallback : reason => {throw reason};
// 5. then方法是可以被链式调用的,后面then方法的回调函数拿到值的是是上一个then方法的回调函数的返回值
let promise2 = new Promise((resolve, reject)=>{
if(this.status === FULFILLED) {
// 8.解决循环调用问题需要的异步
setTimeout(()=>{
try{
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
}catch(e){
reject(e)
}
},0)
}else if(this.status === REJECTED){
setTimeout(()=>{
try{
let x = errorCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
}catch(e){
reject(e)
}
},0)
}else{
// 6.处理异步情况、then方法多次调用情况
this.successCallback.push(()=>{
setTimeout(()=>{
try{
let x = successCallback(this.value)
resolvePromise(promise2, x, resolve, reject)
}catch(e){
reject(e)
}
},0)
});
this.errorCallback.push(()=>{
setTimeout(()=>{
try{
let x = errorCallback(this.reason)
resolvePromise(promise2, x, resolve, reject)
}catch(e){
reject(e)
}
},0)
});
}
})
return promise2
}
}
// 7. 判断x的值是普通值还是promise对象
function resolvePromise(promise2, x, resolve, reject) {
if(promise2 === x){
reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
}
if(x instanceof MyPromise){
// 如果是promise对象,查看promsie对象返回的结果,再根据promise对象返回的结果决定调用
x.then(resolve, reject)
}else{
// 如果是普通值 直接调用resolve
resolve(x)
}
}
- 基本用法
let promise = new MyPromise((resolve, reject) =>{
resolve('suc');
reject('err')
})
promise.then(value =>{
console.log(value);
}, reason=>{
console.log(reason);
})
- 异步逻辑
let promise = new MyPromise((resolve, reject) =>{
setTimeout(() => {
resolve('suc');
},5000)
})
promise.then(value =>{
console.log(value);
}, reason=>{
console.log(reason);
})
- then多次调用
let promise = new MyPromise((resolve, reject) =>{
setTimeout(() => {
resolve('suc');
},2000)
})
promise.then(value =>{
console.log(value);
}, reason=>{
console.log(reason);
})
promise.then(value =>{
console.log(value);
}, reason=>{
console.log(reason);
})
- then链式调用(普通值)
let promise = new MyPromise((resolve, reject) =>{
resolve('suc');
})
promise.then(value =>{
console.log(value);
return 100
}).then(value =>{
console.log(value);
})
- then链式调用(Promise对象)
let promise = new MyPromise((resolve, reject) =>{
resolve('suc');
})
function other(){
return new MyPromise((resolve, reject) =>{
resolve('other')
})
}
promise.then(value =>{
console.log(value);
return other()
}).then(value =>{
console.log(value);
})
- then循环调用Promise的处理
let promise = new MyPromise((resolve, reject) =>{
resolve('suc');
})
let p1 = promise.then(value =>{
console.log(value);
return p1
})
p1.then(() =>{},reason=>{
console.log(reason.message);//Chaining cycle detected for promise #<Promise>
})
- 错误处理
- 执行器
- then的各种情况
- then方法的参数为可选
let promise = new MyPromise((resolve, reject) =>{
resolve('suc');
})
promise
.then()
.then()
.then(value =>{
console.log(value);
})
- all方法
static all (array){
let result = [];
let index = 0;
return new MPromise((resolve, reject) => {
for(let i = 0; i < array.length; i++) {
let current = array[i];
if(current instanceof MyPromise) {
current.then(value => {addData(i, value), reason => reject(reason)})
} else {
addData(i, array[i])
}
}
function addData(key, value) {
result[key] = value;
index++;
if(index === array.length) {
resolve(result);
}
}
})
}
- resolve方法
- 返回一个Promise
static resolve(value){
if(value instanceof MyPromise) return value;
return new MyPromise(resolve => resolve(value));
}
function p1(){
return new MyPromise(function(resolve, reject){
resolve('hello')
})
}
Promise.resolve(10).then(value => console.log(value)) // 10;
Promise.resolve(p1()).then(value => console.log(value)) // hello
- finally方法
- 用于指定不管 Promise 对象最后状态如何,都会执行的操作
finally(callback){
return this.then(value => {
return MyPromise.resolve(callback()).then(()=>value);
}, reason => {
return MyPromise.resolve(callback()).then(()=>{throw reason});
})
}
function p1(){
return new MyPromise(function(resolve, reject){
setTimeout(function(){
resolve('p1')
},2000)
})
}
function p2(){
return new MyPromise(function(resolve, reject){
resolve('p2')
})
}
p2().finally(()=>{
console.log('finally');
return p1()
}).then(value=>{
console.log(value);
},reason=>{
console.log(reason);
})
- catch方法
catch(errorCallback){
return this.then(undefined, errorCallback)
}
function p2(){
return new MyPromise(function(resolve, reject){
resolve('p2')
})
}
p2()
.then(value=>{console.log(value)})
.catch(reason=>{console.log(reason)})
- allSeettled,返回所有promise的状态和结果
function PromiseAllSettled(promiseArray) {
return new Promise(function (resolve, reject) {
//判断参数类型
if (!Array.isArray(promiseArray)) {
return reject(new TypeError('arguments muse be an array'))
}
let counter = 0;
const promiseNum = promiseArray.length;
const resolvedArray = [];
for (let i = 0; i < promiseNum; i++) {
Promise.resolve(promiseArray[i])
.then((value) => {
resolvedArray[i] = {
status: 'fulfilled',
value
};
})
.catch(reason => {
resolvedArray[i] = {
status: 'rejected',
reason
};
})
.finally(() => {
counter++;
if (counter == promiseNum) {
resolve(resolvedArray)
}
})
}
})
}