《Promise方法使用介绍》


2020-08-05 上次更新时间:8/6/2020, 11:55:20 PM 0 javascript

https://www.jianshu.com/p/d8a901dd72ac

// 执行顺序
var p41 = new Promise((resolve, reject) => {
    reject('p41 error')
    console.log('p41---------')
}).catch(err => {
    console.log('hahhahah')
})

var p42 = new Promise((resolve, reject) => {
    reject('p42 err')
    console.log('p42---------')
}).catch(err => {
    console.log('kekekeke')
    return err;
})

var p43 = new Promise((resolve, reject) => {
    reject('p43 err')
    console.log('p43---------')
}).catch(err => {
    console.log('xixixi')
    return err;
})

// 返回第一个完成的 promise 值
Promise.race([p43, p41, p42]).then((res) => {
  console.log('res', res) 
}, (err) => {
    console.log('err', err) // p41 error
})
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

# 基本使用

让一个函数拥有 promise 功能,只需让其返回一个promise即可。

function myAsyncFunction(url) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open("GET", url);
        xhr.onload = () => resolve(xhr.responseText);
        xhr.onerror = () => reject(xhr.statusText);
        xhr.send();
    });
  };
1
2
3
4
5
6
7
8
9

# Promise.then()

# Promise.catch()

# Promise.finally()

# Promise.resolve()

返回一个状态为 fulfilled 的 Promise 对象

# 基础用法

Promise.resolve('Hello').then((res)=> {
  console.log(res); // Hello
})
1
2
3

# 应用场景

可以将现有对象专为Promise对象

var jsPromise = Promise.resolve($.ajax('/whatever.json'));
console.log(jsPromise) // Promise
1
2

# 使用注意

  • 参数是一个 Promise 实例:Promise.resolve将不做任何修改、原封不动地返回这个实例。
var p1 = new Promise((resolve, reject) => {
  resolve('p1 success')
})
Promise.resolve(p1) // Promise 实例
1
2
3
4
  • 参数是一个thenable对象(具有then方法的对象):将这个对象转为 Promise 对象,然后就立即执行thenable对象的then方法
var thenable = {
  then: function(resolve, reject) {
    resolve(42);
  }
};
var p1 = Promise.resolve(thenable)

console.log(p1) // status: fulfilled,value: 42

p1.then(res => {
  console.log(res) // 42
})
1
2
3
4
5
6
7
8
9
10
11
12
  • 参数不是具有then方法的对象,或根本就不是对象:返回一个新的 Promise 对象,状态为resolved
var normalObj = {
  name: 'jack'
};
var p2 = Promise.resolve(normalObj)

console.log(p2) // status: fulfilled,value: { name: 'jack'}

p2.then(res => {
  console.log(res) // { name: 'jack'}
})
1
2
3
4
5
6
7
8
9
10
  • 不带有任何参数:直接返回一个resolved状态的 Promise 对象。
const p = Promise.resolve();

p.then(function () {
  // ...
});
1
2
3
4
5
  • 立即resolve的 Promise 对象,是在本轮“事件循环”(event loop)的结束时,而不是在下一轮“事件循环”的开始时。

原因:因为promise.resolve后的方法是属于微任务,所以会在当轮事件循环的宏任务结束后按顺序执行微任务

setTimeout(function () {
  console.log('three');
}, 0);

Promise.resolve().then(function () {
  console.log('two');
});

console.log('one');
// one
// two
// three
1
2
3
4
5
6
7
8
9
10
11
12

# Promise.reject()

返回一个状态为 rejected 的 Promise 对象

# 基础用法

Promise.reject('Error').then(null, (err) =>{
  console.log(err); // Error
})
Promise.reject('Error').catch((err) =>{
  console.log(err); // Error
})
1
2
3
4
5
6

# Promise.all()

所有都成功,才会resolve,只要有一个失败,就触发reject

# 基础用法

var p11 = new Promise((resolve, reject) => {
    resolve('p11 success');
})
var p12 = new Promise((resolve, reject) => {
    setTimeout(() =>{
        resolve('p12 success');
    }, 1000)
})

var p13 = "123";

var p14 = new Promise((resolve, reject) => {
    setTimeout(() =>{
        reject('p14 error');
    }, 2000)
})

// 传入一个 promise 数组
Promise.all([p11, p12, p13]).then((res) => {
    console.log(res) // 延迟 1s 后输出 -> ["p11 success", "p12 success", "123"]
})

// 数组中含有一个 rejected 状态的promise
Promise.all([p11, p12, p13, p14]).catch((err) => {
    console.log(err) // 延迟 2s 后输出 -> p14 error
})

// 传入的 promise 没有resolve 状态
Promise.all([p14]).catch((res) => {
    console.log(res) // p14 error
})

// 传入一个字符串
var str = "123"
Promise.all(str).then((res) => {
    console.log(res) // ["1", "2", "3"]
})

// 传入一个不含promise的数组
var arr = [1, "b", {}]
Promise.all(arr).then((res) => {
    console.log(res) // [1, "b", {}]
})

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

# 使用注意

  • 注意,如果作为参数的 Promise 实例,自己定义了catch方法,那么它一旦被rejected,并不会触发Promise.all()的catch方法。
var p11 = new Promise((resolve, reject) => {
    resolve('p11 success');
})
.then(res => res)
.catch(err => err) 

var p12 = new Promise((resolve, reject) => {
    throw new Error('报错了');
})
.then(res => res)
.catch(err => err) // 自定义 catch 方法,此时 p12 是一个resolve状态的promise

Promise.all([p11, p12]).then((res) => {
    console.log(res)  // ["p11 success", Error: 报错了]
}).catch((err) => {
  console.log(err) // 不会进入这里
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

如果 rejected 状态的实例没有catch方法,则此时可被 promise.all 的 catch

var p11 = new Promise((resolve, reject) => {
    resolve('p11 success');
})
.then(res => res)
.catch(err => err) 

var p12 = new Promise((resolve, reject) => {
    throw new Error('报错了'); // 没有 catch 方法,此时 p12 是一个rejected 状态的 promise
})

Promise.all([p11, p12]).then((res) => {
    console.log(res)  // 不会进入这里
}).catch((err) => {
  console.log('111', err) // Error: 报错了
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Promise.allSettled()

只要所有传入promise都完成,不管状态是 resolve 还是rejected,都会触发

var p21 = new Promise((resolve, reject) => {
  resolve('p21 success');
})
var p22 = new Promise((resolve, reject) => {
  reject('p22 error')
})

Promise.allSettled([p21, p22, p23]).then((res) => {
  console.log(res) // 输出一个数组
  // [
  //   {
  //     status: "fulfilled"
  //     value: "p21 success"
  //   },
  //   {
  //     status: "rejected"
  //     value: "p22 error"
  //   }
  // ]
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# Promise.any()

当第一个成功的 promise resolve返回时触发,如果没有 resolve 状态的 promise,则会报错。

Promise.any() 方法尚未被所有的浏览器完全支持。它当前处于 TC39 第四阶段草案(Stage 4)

var p31 = new Promise((resolve, reject) => {
    reject('p31 error');
})
var p32 = new Promise((resolve, reject) => {
    setTimeout(resolve, 500, "最终完成");
})
var p33 = new Promise((resolve, reject) => {
    setTimeout(resolve, 100, "最快完成");
})

// 传入一个 promise 数组
Promise.any([p31, p32, p33]).then((res) => {
    console.log(res) // 最快完成
})

// 传入的 promise 没有resolve 状态
Promise.any([p31]).then((res) => {
    console.log(res) // "AggregateError: No Promise in Promise.any was resolved"
})

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

# Promise.race()

返回第一个 promise 完成的值,无论是成功还是失败。如果多个 promise 同时返回,则按传入顺序返回第一个。

# 基础用法

var p41 = new Promise((resolve, reject) => {
    reject('p41 error')
})

var p42 = new Promise((resolve, reject) => {
    resolve('p42 success')
})
var p43 = new Promise((resolve, reject) => {
    setTimeout(resolve, 500, "最慢完成");
})

// 返回第一个完成的 promise 值
Promise.race([p41, p42, p43]).then(null, (err) => {
    console.log(err) // p41 error
})

// 假设都没有延迟,因为promise实例化时立即执行,所以会按执行顺序,返回第一个的值
Promise.race([p42, p41, p43]).then((res) => {
    console.log(res) // p42 success
})

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

# 应用场景

可以设置如果指定时间内没有获得结果,就将 Promise 的状态变为reject,否则变为resolve。

var p44 = new Promise((resolve, reject) => {
    setTimeout(resolve, 5000, "5s才返回");
})
var p45 = new Promise((resolve, reject) => {
    setTimeout(reject, 3000, "3s不返回就error");
})
Promise.race([p44, p45])
.then(console.log)
.catch(console.error); // 3s不返回就error
1
2
3
4
5
6
7
8
9

# 使用注意

Promise.reject()方法的参数,会原封不动地作为reject的理由,变成后续方法的参数

var thenable = {
  then(resolve, reject) {
    reject('出错了');
  }
};

Promise.reject(thenable)
.catch(e => {
  console.log(e === thenable) // true => 输出了整个 thenable 对象,而不是 ”出错了“
})
1
2
3
4
5
6
7
8
9
10
  • 实现一个promise
  • 如何实现 promise.all
  • 如何实现 promise.finally

关于Fetch

  1. fetch是Es6的一个api,是一个获取资源的接口,包括跨域。就是一个类似与ajax的api
  2. 可以使用fetch polyfill兼容
  3. fetch无论成功与否,都会返回一个promise对象
  4. fetch核心在于HTTP接口的抽象

关于fetch与jq.ajax不同的地方

  1. 即便是http响应状态码为400/500,fetch()返回的promise也是resolve,只是resolve的of属性为false。仅当故障或者请求被阻止的时候,才会被标记为reject
  2. 默认下,fetch不会从服务端发送或接受任何cookies,如果需要,则要设置credentials 选项
// 还有其他自定义参数
myHeaders = new Headers({
  "Content-Type": "text/plain",
  "Content-Length": content.length.toString(),
  "X-Custom-Header": "ProcessThisImmediately",
});
myHeaders.append("h_shop", shopNo);

fetch(url,{}).then(function(response) {
  // return 结果,被下一次then调用
  return response;
}).then(function(response) {
  // response.ok:状态码在200~299都是ok
  if(response.ok) {
    console.log('成功')
  } else {
    console.log('网络故障类错误');
  }
}).catch(function(error) {
  // 捕捉错误
});;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

参考文章:

https://www.jianshu.com/p/d8a901dd72ac

上次更新时间: 8/6/2020, 11:55:20 PM