# 异步编程promise

# 状态

  • 状态值
    • pending 连接状态
    • fulfilled 成功状态
    • reject 拒绝状态
  • 状态是不可逆的,状态谁先改变则是谁
  • 有两个回调函数
    • resolve 成功
    • reject 失败

# then

  • 包含两个回调函数,一个成功回调,一个失败回调
new Promise((resolve, reject) => {
    resolve('成功')
}).then(result => {
    console.log(result)
})
new Promise((resolve, reject) => {
    reject('失败')
}).then(null, reason => {
    console.log(reason)
})
1
2
3
4
5
6
7
8
9
10
  • 链式调用,优先执行先定义的 then 方法

    new Promise((resolve, reject) => {
        resolve('成功')
    }).then(res => {
        console.log(res)
    }).then(res => {
        console.log(res)
    })
    // 成功, undefined
    
    1
    2
    3
    4
    5
    6
    7
    8
  • 每个 then 方法返回的也是一个 promise

    let p1 = new Promise((resolve, reject) => {
        resolve('成功')
    })
    
    let p2 = p1.then(value => {
        console.log(value)
    }, reason => {
        console.log(reason)
    })
    
    setTimeout(() => {
        console.log(p1)
        console.log(p2)
    })
    
    // ’成功', p1, p2
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
  • 多个 then 方法时,下一个 then 方法是对上一个 then 返回(return)的值进行处理,且默认状态是 resolve 成功

    new Promise((resolve, reject) => {
        reject("失败");
    }).then(
        result => console.log(result),
        reason => console.log(reason)
    ).then(
        result => console.log("成功"),
        reason => console.log("失败")
    )
    // 失败, 成功
    
    new Promise((resolve, reject) => {
        resolve("成功");
    }).then(
        result => {
            return new Promise((resolve, reject) => {
                reject('第二个错误promise')
            })
        },
        reason => console.log(reason)
    ).then(
        result => console.log("成功"),
        reason => console.log('error ' + reason)
    )
    // error 第二个错误promise
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
  • 其它类型的 promise 封装

    new Promise((resolve, reject) => {
        resolve("成功");
    }).then(
        result => {
            class Fn {
               then(resolve, reject){
                    resolve('这是对象')
                } 
            }
            return new Fn()
        }
    ).then(
        result => console.log(result),
        reason => console.log('error ' + reason)
    )
    // 这是对象
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16

# catch

  • 可以捕获 promise 抛出的错误
  • 建议统一将方法放在最后执行捕获
  • 前面 then 方法做了错误回调处理,则不执行 catch 方法
 new Promise((resolve, reject) => {
    reject("失败");
  }).then(
    result => console.log(result),
    reason => console.log('error ' + reason)
  ).catch(err => {
    console.log(err);
  }) 
// error 失败
1
2
3
4
5
6
7
8
9

# finally

无论状态是resolvereject 都会执行此动作,finally 与状态无关。

new Promise((resolve, reject) => {
    resolve("成功");
}).then(
    result => console.log(result)
).catch(err => {
    console.log(err);
}).finally(() => {
    console.log("resolve/reject状态都会执行")
})
// 成功, resolve/reject状态都会执行
1
2
3
4
5
6
7
8
9
10

# 使用promise异步加载图片

function loadImage(src, id) {
    return new Promise((resolve, reject) => {
        const image = new Image()
        image.src = src
        image.onload = () => {
            resolve(image)
        }
        image.onerror = reject
        document.querySelector(id).appendChild(image)
    })
}
1
2
3
4
5
6
7
8
9
10
11

# 定时器封装

function timeout(delay = 1000) {
    return new Promise(resolve => setTimeout(resolve, delay))
}
timeout(2000).then(() => {
   console.log('2秒后输出')
   return timeout(1000)
}).then(() => {
    console.log('再过1秒后输出')
})
1
2
3
4
5
6
7
8
9

# 其他接口方法

# resolve

使用 promise.resolve 方法可以快速的返回一个 promise 对象

Promise.resolve("Mondo").then(value => {
  console.log(value); // Mondo
});
1
2
3

缓存查询数据

function query(name) {
  const cache = query.cache || (query.cache = new Map());
  if (cache.has(name)) {
    console.log("缓存");
    return Promise.resolve(cache.get(name));
  }
  return ajax(`http://test.com?name=${name}`).then(
    res => {
      cache.set(name, response);
      console.log("没走缓存");
      return res;
    }
  );
}
query("Mondo").then(res => {
  console.log(res);
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# reject

Promise.resolve 类似,reject 生成一个失败的promise

new Promise((resolve, reject) => {
    resolve('成功')
}).then(value => {
    if (value !== 'mondo') {
        return Promise.reject('参数错误')
    }
}).catch(error => {
    console.log(error) // 参数错误
})
1
2
3
4
5
6
7
8
9

# all

使用Promise.all 方法可以同时执行多个并行异步操作

  • 任何一个 Promise 执行失败就会调用 catch方法
  • 适用于一次发送多个异步操作
  • 参数必须是可迭代类型,如Array/Set
  • 成功后返回 promise 结果的有序数组
const p1 = new Promise((resolve, reject) => {
  resolve("第一个Promise");
});
const p2 = new Promise((resolve, reject) => {
  resolve("第二个Promise");
});
Promise.all([p1, p2]).then(res => {
  console.log(res); // ['第一个Promise', '第二个Promise']
}).catch(error => {
  console.log(error);
});
1
2
3
4
5
6
7
8
9
10
11

# allSettled

Promise.allSettled 用于处理多个promise ,只关注执行完成,不关注是否全部执行成功,allSettled 状态只会是fulfilled

const p1 = new Promise((resolve, reject) => {
  resolve("第一个Promise");
});
const p2 = new Promise((resolve, reject) => {
  reject("第二个Promise");
});
Promise.allSettled([p1, p2]).then(res => {
  console.log(res);
})
1
2
3
4
5
6
7
8
9

打印出的来值为

# race

Promise.race 批量处理多个 Promise,谁先返回状态就执行哪个

  • 以最先返回的 promise 为准
  • 如果最先返加的状态为rejected 那么整个promiserejected执行catch
  • 如果参数不是promise,内部将自动转为promise
const p1 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve("第一个Promise");
  }, 1000)
});
const p2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject("第二个Promise");
  })
});
Promise.race([p1, p2]).then(res => {
  console.log(res);
}).catch(error => {
  console.log(error) // 第二个Promise
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 任务队列

如果 then 返回一个 promise 时,后面的 then 就是对返回的 promise 进行处理,只有当一个 promise 状态 resolve 后,下一个 then 方法才会执行

let promise = Promise.resolve();
let p1 = promise.then(() => {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(`p1`);
      resolve();
    }, 2000);
  });
});
p1.then(() => {
  return new Promise((a, b) => {
    setTimeout(() => {
      console.log(`p2`);
    }, 1000);
  });
})
// p1, p2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

实现一个队列输出

// 使用map
function queue(num) {
  let promise = Promise.resolve()
  num.map(v => {
    promise = promise.then(_ => {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log(v)
          resolve()
        }, 1000)
      })
    })
  })
}
// 使用reduce
function queue(num) {
  let promise = Promise.resolve()
  num.reduce((promise, v) => {
    return promise.then(_ => {
      return new Promise(resolve => {
        setTimeout(() => {
          console.log(v)
          resolve();
        }, 1000)
      })
    })
  }, Promise.resolve())
}
queue([1, 2, 3, 4, 5, 6])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# async与await语法糖

# async

在函数前加上 async,函数将返回一个 promise,可以像使用 promise 一样使用

  • 无论函数有没有返回值,promise 状态都是 resolve 完成状态
async function fn() {
    return 'mondo'
}
console.log(fn())
fn().then(res => {
    console.log(re)
})
1
2
3
4
5
6
7

# await

使用 await 会等待 promise 执行完

  • await 后面一般是promise,如果不是直接返回
  • await 必须放在 async 定义的函数中使用
  • await 用于替代 then 使编码更优雅
async function fn() {
  let promise = new Promise(resolve => {
    setTimeout(() => {
      resolve('mondo')
    }, 1000)
  })
  let a = await promise
  console.log(a)
}
fn()
1
2
3
4
5
6
7
8
9
10

# async 延时函数

async function sleep(delay = 2000) {
    return new Promise(resolve => {
        setTimeout(() => {
            resolve()
        }, delay)
    })
}
async function show(arr) {
    for (const v of arr) {
        await sleep()
        console.log(v)
    }
}
show([1, 2])
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# class 与 await 的结合

class User {
    constructor(name) {
        this.name = name
    }
    // 定义then方法,返回 resolve 状态
    then(resolve, reject) {
        setTimeout(() => {
            resolve(this.name)
        }, 1000)
    }
}
async function get() {
    let user = await new User('mondo')
    console.log(user)
}
get() // mondo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# async 错误处理

  • 使用 catch 捕获错误

    async function fn() {
        throw new Error('error')
    }
    fn().catch(err => {
        console.log(err)
    })
    
    1
    2
    3
    4
    5
    6
  • 使用 try...catch 捕获错误

    async function fn() {
        try {
            const a = await fn1()
          	const b = await fn2()
            return b
        } catch (error => {
            console.log(error)
    	})
    }
    fn()
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

# await 并行执行

async function p1() {
    return 'mondo'
}
async function p2() {
    return 'imondo.cn'
}
async function fn() {
    const h1 = p1()
    const h2 = p2()
    console.log(h1, h2)
    const v1 = await h1
    const v2 = await h2
    console.log(v1, v2)
}
fn() // 同时打印 mondo imondo.cn

// 或者

async function fn1() {
  const res = await Promise.all([p1(), p2()])
  console.log(res)
}
fn1() // 同时打印 ['mondo', 'imondo.cn']

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 宏任务与微任务执行顺序

  • 同步任务优先执行

  • 微任务优先宏任务执行

  • 微任务 promise

  • 宏任务 setTimeout

setTimeout(() => {
    console.log(1)
}, 0)
new Promise(reslove => {
    reslove()
    console.log(2)
}).then(() => {
    console.log(3')
})
console.log(4) // 2,4,3,1
1
2
3
4
5
6
7
8
9
10

# 手写一个Promise

  • 实现promise基本用法
  • 实现then链式调用方法
  • 实现all方法
  • 实现race方法
class MoPromise {
  static PENDING = "pending";
  static FULFILLED = "fulfilled";
  static REJECT = "reject";
  constructor(executor) {
    this.status = MoPromise.PENDING;
    this.value = null;
    this.callbacks = [];
    // 出现异常时执行reject方法
    try {
      executor(this.resolve.bind(this), this.reject.bind(this));
    } catch (error) {
      this.reject(error);
    }
  }

  resolve(value) {
    // 只有pending状态下才执行,且状态变了后不可修改
    if (this.status === MoPromise.PENDING) {
      this.status = MoPromise.FULFILLED;
      this.value = value;
      setTimeout(() => {
        this.callbacks.map(callback => {
          callback.onFulfilled(value);
        });
      });
    }
  }

  reject(reason) {
    if (this.status === MoPromise.PENDING) {
      this.status = MoPromise.REJECT;
      this.value = reason;
      setTimeout(() => {
        this.callbacks.map(callback => {
          callback.onReject(reason);
        });
      });
    }
  }

  then(onFulfilled, onReject) {
    // 当回调函数没传时,定义默认函数
    if (typeof onFulfilled !== "function") {
      onFulfilled = () => this.value; // then穿透传值
    }
    if (typeof onReject !== "function") {
      onReject = () => this.value;
    }
    // 返回promise,实现链式操作
    let promise = new MoPromise((resolve, reject) => {
      // 准备状态处理,以后需要执行的任务队列
      if (this.status === MoPromise.PENDING) {
        this.callbacks.push({
          onFulfilled: value => {
            this.parse(promise, onFulfilled(value), resolve, reject);
          },
          onReject: value => {
            this.parse(promise, onReject(value), resolve, reject);
          }
        });
      }
      // 只有状态改变 才执行方法
      if (this.status === MoPromise.FULFILLED) {
        // 放置在任务队列,实现异步操作
        setTimeout(() => {
          this.parse(promise, onFulfilled(this.value), resolve, reject);
        });
      }

      if (this.status === MoPromise.REJECT) {
        setTimeout(() => {
          this.parse(promise, onReject(this.value), resolve, reject);
        });
      }
    });
    return promise;
  }

  parse(promise, result, resolve, reject) {
    if (promise === result) {
      throw new TypeError("不可返回相同类型");
    }
    try {
      // 如果then返回promise
      if (result instanceof MoPromise) {
        result.then(resolve, reject);
      } else {
        resolve(result);
      }
    } catch (error) {
      reject(error);
    }
  }

  static resolve(value) {
    return new MoPromise((resolve, reject) => {
      if (value instanceof MoPromise) {
        value.then(resolve, reject);
      } else {
        resolve(value);
      }
    });
  }

  static reject(value) {
    return new MoPromise((resolve, reject) => {
      if (value instanceof MoPromise) {
        value.then(resolve, reject);
      } else {
        reject(value);
      }
    });
  }

  static all(promises) {
    const values = [];
    return new MoPromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(
          value => {
            values.push(value);
            if (values.length === promises.length) {
              resolve(values);
            }
          },
          reason => {
            reject(reason);
          }
        );
      });
    });
  }

  static race(promises) {
    return new MoPromise((resolve, reject) => {
      promises.forEach(promise => {
        promise.then(
          value => {
            resolve(value);
          },
          reason => {
            reject(reason);
          }
        );
      });
    });
  }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
更新于: 2/12/2020, 8:50:45 AM