Promise的状态

实例对象的一个内置属性PromiseState

  1. pending 悬而未决的变为resolved 成功的
  2. pending变为rejected 失败的

说明:只有这2种,且一个promise对象只能改变一次无论变为成功还是失败,都会有一个结果数据成功的结果数据一般称为value,失败的结果数据一般称为reason

Promise 对象的值

实例对象中的一个属性 PromiseResult 保存着异步任务成功/失败的结果

  1. resolve(result)
  2. reject(result)

Promise的基本流程

image.png

API
Ⅰ- Promise 构造函数: Promise (excutor) {}

(1) executor 函数: 执行器 (resolve, reject) => {} 函数类型的参数
(2) resolve 函数: 内部定义成功时我们调用的函数 value => {}
(3) reject 函数: 内部定义失败时我们调用的函数 reason => {}
说明: executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行,换话说Promise支持同步也支持异步操作

1
2
3
4
5
    let p = new Promise((resolve,reject)=>{
console.log(111);
})
console.log(222);
// 先输出111 再输出222

Ⅱ-Promise.prototype.then 方法: (onResolved, onRejected) => {}

(1) onResolved 函数: 成功的回调函数 (value) => {}
(2) onRejected 函数: 失败的回调函数 (reason) => {}
说明: 指定用于得到成功 value 的成功回调和用于得到失败 reason 的失败回调 返回一个新的 promise 对象

Ⅲ-Promise.prototype.catch 方法: (onRejected) => {}

(1) onRejected 函数: 失败的回调函数 (reason) => {}
说明: then()的语法糖, 相当于: then(undefined, onRejected)
(2) 异常穿透使用:当运行到最后,没被处理的所有异常错误都会进入这个方法的回调函数中

Ⅳ-Promise.resolve 方法: (value) => {}

不属于实例对象,属于函数对象 快速返回一个成功的promise对象
(1) value: 成功的数据或 promise 对象
说明: 返回一个成功/失败的 promise 对象,直接改变promise状态

  • 如果传入的参数为非Promise类型的对象,则返回的结果为成功的Promise对象
  • 如果传入的参数为Promise对象,则参数的结果决定了resolve的结果
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    let p1 = Promise.resolve(999);
    console.log(p1)
    let p2 = Promise.resolve(new Promise((resolve, reject)=>{
    // resolve('ok') resolve和reject同时写的话,只会调用最前面的一个
    reject('error') // 参数的状态决定了p2的状态
    }))
    p2.catch(reason => {
    console.log(reason)
    })
    console.log(p2);

Ⅴ-Promise.reject 方法: (reason) => {}

不属于实例对象,属于函数对象 快速返回一个失败的promise对象
(1) reason: 失败的原因
说明: 返回一个失败的 promise 对象,直接改变promise状态,状态永远都是失败的

1
2
3
4
5
6
7
8
9
10
let p1 = Promise.reject(999);
console.log(p1)
let p2 = Promise.reject(new Promise((resolve, reject)=>{
resolve('ok')
// reject('error')
}))
p2.catch(reason => {
console.log(reason)
})
console.log(p2);

image.png

Ⅵ-Promise.all 方法: (promises) => {}

promises: 包含 n 个 promise 的数组
说明: 返回一个新的 promise, 只有所有的 promise 都成功才成功, 只要有一个失败了就直接失败
成功的结果是所有成功的promise组成的结果,失败的结果是失败的promise组成的结果

1
2
3
4
5
let p1 = new Promise((resolve, reject) => { resolve('成功');  })
let p2 = Promise.reject('错误错误错误');
let p3 = Promise.resolve('也是成功')
const result = Promise.all([p1, p2, p3]);
console.log(result);

只要任何一个输入的 promise 的 reject 回调执行或者输入不合法的 promise 就会立即抛出错误,并且 reject 的是第一个抛出的错误信息。

Ⅶ-Promise.race 方法: (promises) => {}

(1) promises: 包含 n 个 promise 的数组
说明: 返回一个新的 promise, 第一个完成的 promise 的结果状态就是最终的结果状态,一旦迭代器中的某个 promise 解决或拒绝,返回的 promise 就会解决或拒绝。
如p1延时,开启了异步,内部正常是同步进行,所以p2>p3>p1,结果是P2

1
2
3
4
5
6
7
8
9
10
11
12
13
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one'); //这种表示有点点奇怪
});

const promise2 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'two');
});

Promise.race([promise1, promise2]).then((value) => {
console.log(value);
// Both resolve, but promise2 is faster
});
// expected output: "two"


Promise的几个关键问题

Ⅰ-如何改变 promise 的状态?

(1) resolve(value): 如果当前是 pending 就会变为 resolved
(2) reject(reason): 如果当前是 pending 就会变为 rejected
(3) 抛出异常: 如果当前是 pending 就会变为 rejected

Ⅱ-一个 promise 指定多个成功/失败回调函数, 都会调用吗?

当 promise 改变为对应状态时都会调用,改变状态后,多个回调函数都会调用,并不会自动停止
如果状态是pending且没有发生改变时,则回调函数不会调用

1
2
3
4
5
6
7
8
9
10
11
12
13
let p = new Promise((resolve, reject) => {  resolve('OK');});
///指定回调 - 1
p.then(value => { console.log(value); });
//指定回调 - 2
p.then(value => { alert(value);});

let p = new Promise((resolve, reject) => {
resolve('OK');
}).then(value => {
console.log(value); //OK
}).then(value => {
alert(value); // undefined
});

Ⅲ- 改变 promise 状态和指定回调函数谁先谁后?

(1) 都有可能, 正常情况下是先指定回调再改变状态, 但也可以先改状态再指定回调
先指定回调再改变状态(异步):先指定回调–> 再改变状态 –>改变状态后才进入异步队列执行回调函数
先改状态再指定回调(同步):改变状态 –>指定回调 并马上执行回调
(2) 如何先改状态再指定回调? –>注意:指定并不是执行
① 在执行器中直接调用 resolve()/reject() –>即,不使用定时器等方法,执行器内直接同步操作
② 延迟更长时间才调用 then() –>即,在.then()这个方法外再包一层例如延时器这种方法
(3) 什么时候才能得到数据? 即 回调函数什么时候执行
① 如果先指定的回调, 那当状态发生改变时, 回调函数就会调用, 得到数据
② 如果先改变的状态, 那当指定回调时, 回调函数就会调用, 得到数据

1
2
3
4
5
6
7
let p = new Promise((resolve, reject) => {
//异步写法,这样写会先指定回调,再改变状态
setTimeout(() => {resolve('OK'); }, 1000);
//这是同步写法,这样写会先改变状态,再指定回调
resolve('OK');
});
p.then(value => {console.log(value);}, reason => {})

Ⅳ-promise.then()返回的新 promise 的结果状态由什么决定?

(1) 简单表达: 由 then()指定的回调函数执行的结果决定
(2) 详细表达:
① 如果抛出异常, 新 promise 变为 rejected, reason 为抛出的异常
② 如果返回的是非 promise 的任意值, 新 promise 变为 resolved, value 为返回的值
③ 如果返回的是另一个新 promise, 此 promise 的结果就会成为新 promise 的结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let p = new Promise((resolve, reject) => {
resolve('ok');
});
//执行 then 方法
let result = p.then(value => {
console.log(value);
// 1. 抛出错误 ,变为 rejected
throw '出了问题';
// 2. 返回结果是非 Promise 类型的对象,新 promise 变为 resolved,结果为521
return 521;
// 3. 返回结果是 Promise 对象,此 promise 的结果就会成为新 promise 的结果
return new Promise((resolve, reject) => {
// resolve('success');
reject('error');
});
}, reason => {
console.warn(reason);
});

Ⅴ- promise 如何串连多个操作任务?

(1) promise 的 then()返回一个新的 promise, 可以开成 then()的链式调用
(2) 通过 then 的链式调用串连多个同步/异步任务,这样就能用then()将多个同步或异步操作串联成一个同步队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok')
}, 1000);
});

let result = p.then(value => {
return new Promise((resolve, reject) => {
resolve("success");
})
}).then(value => {
console.log(value) // success
// 没有写返回值,所以是undefined,是非promise对象,所以是成功的结果
}).then(value => {
// 该promise的结果由第二个then中的返回值决定
console.log(value) // undefined
});
console.log(result)
// 如果在1s内打开,则状态是pending;如果大于1s打开,则状态是fulfilled

Ⅵ-promise 异常传透

  • 当使用 promise 的 then 链式调用时, 可以在最后指定失败的回调
  • 前面任何操作出了异常, 都会传到最后失败的回调中处理
  • 注:可以在每个then()的第二个回调函数中进行err处理,也可以利用异常穿透特性,到最后用catch去承接统一处理,两者一起用时,前者会生效(因为err已经将其处理,就不会再往下穿透)而走不到后面的catch
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    getJSON('./hong.json')
    .then(function (posts) {
    throw new Error('抛出异常')
    })
    .then(res => console.log(res), e => console.log('被then的错误回调捕获', e))
    .catch(function (error) {
    // 处理 getJSON 和 前一个回调函数运行时发生的错误
    console.log('错误捕获: ', error);
    });
    //执行结果: 被then的错误回调捕获 Error: 抛出异常

    /******************** 利用异常穿透 ****************************************/
    getJSON('./hong.json')
    .then(function (posts) {
    throw new Error('抛出异常')
    })
    .then(res => console.log(res)) //此处差异,不指定 reject 回调,利用异常穿透传到最后
    .catch(function (error) {
    console.log('错误捕获: ', error);
    });
    //执行结果: 错误捕获: Error: 抛出异常

Ⅶ- 中断 promise 链?

在关键问题2中,可以得知,当promise状态改变时,他的链式调用都会生效,那如果我们有这个一个实际需求:我们有5个then(),但其中有条件判断,如当我符合或者不符合第三个then条件时,要直接中断链式调用,不再走下面的then,该如何?
(1) 当使用 promise 的 then 链式调用时, 在中间中断, 不再调用后面的回调函数
(2) 办法: 在回调函数中返回一个 pendding 状态的promise 对象 那么因为状态是pending,所以then就不会继续被调用了,实现了promise链的中断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('ok');
// reject('error')
}, 1000);
});
p.then(value => {
console.log(111);
return new Promise(() => {}); // 有且只有这一种方式
}).then(value => {
console.log(222);
throw 'error!!';
}).then(value => {
console.log(333);
}).catch(reason => {
console.warn(reason)
});

手写Promise

疑点

1
2
3
const promise1 = new Promise((resolve, reject) => {
setTimeout(resolve, 500, 'one'); //这种表示有点点奇怪
});

为什么result的值为空

1
2
3
4
5
6
7
8
9
10
11
12
13
function foo() {
let result = ''
var p = new Promise((resolve, reject) => {
resolve('hello world!')
});
p.then(value => {
result = value
})
return result
}

result = foo()
console.log(result) // ""