美文网首页
ES6 Promise

ES6 Promise

作者: Cherry丶小丸子 | 来源:发表于2022-12-21 16:32 被阅读0次

    Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大

    ES6 规定,Promise 对象是一个构造函数,用来生成 Promise 实例

    1、Promise 的特点
    • 对象的状态不受外界影响,有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)
    • 一旦状态改变,就不会再变,任何时候都可以得到这个结果,只有两种可能:从 pending 变为 fulfilled 和从 pending 变为 rejected
    2、Promise 的基本用法
    const promise = new Promise(function(resolve, reject) {
        // ... some code
    
        if (/* 异步操作成功 */){
            resolve(value);
        } else {
            reject(error);
        }
    });
    
    resolve 函数的作用是,将 Promise 对象的状态从 “未完成” 变为 “成功”(即从 pending 变为 resolved)
    reject 函数的作用是,将 Promise 对象的状态从 “未完成” 变为 “失败”(即从 pending 变为 rejected)
    

    Promise实例生成以后,可以用 then 方法分别指定 resolved 状态和 rejected 状态的回调函数

    promise.then(function(value) {
        // success
    }, function(error) {
        // failure
    });
    
    then 方法可以接受两个回调函数作为参数。第一个回调函数是 Promise 对象的状态变为 resolved 时调用,
    第二个回调函数是 Promise 对象的状态变为 rejected 时调用,这两个函数都是可选的,不一定要提供
    

    Promise 新建后就会立即执行

    let promise = new Promise(function(resolve, reject) {
        console.log('Promise');
        resolve();
    });
    
    promise.then(function() {
        console.log('resolved.');
    });
    
    console.log('Hi!');
    
    // Promise
    // Hi!
    // resolved
    

    如果调用 resolve 函数和 reject 函数时带有参数,那么它们的参数会被传递给回调函数。reject 函数的参数通常是 Error 对象的实例,表示抛出的错误;resolve 函数的参数除了正常的值以外,还可能是另一个 Promise 实例,比如像下面这样

    const p1 = new Promise(function (resolve, reject) {
        // ...
    });
    
    const p2 = new Promise(function (resolve, reject) {
        // ...
        resolve(p1);
    })
    
    上面代码中,p1 和 p2 都是 Promise 的实例,但是 p2 的 resolve 方法将 p1 作为参数,即一个异步操作的结果是返回另一个异步操作
    
    注意,这时 p1 的状态就会传递给 p2,也就是说,p1 的状态决定了 p2 的状态。
    如果 p1 的状态是 pending,那么 p2 的回调函数就会等待 p1 的状态改变;
    如果 p1 的状态已经是 resolved 或者 rejected,那么 p2 的回调函数将会立刻执行。
    

    注意,调用 resolve 或 reject 并不会终结 Promise 的参数函数的执行

    new Promise((resolve, reject) => {
        resolve(1);
        console.log(2);
    }).then(r => {
        console.log(r);
    });
    // 2
    // 1
    
    上面代码中,调用 resolve(1) 以后,后面的 console.log(2) 还是会执行,并且会首先打印出来。
    这是因为立即 resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。
    

    一般来说,调用 resolve 或 reject 以后,Promise 的使命就完成了,后继操作应该放到 then 方法里面,而不应该直接写在 resolve 或 reject 的后面。所以,最好在它们前面加上 return 语句,这样就不会有意外

    new Promise((resolve, reject) => {
        return resolve(1);
        // 后面的语句不会执行
        console.log(2);
    })
    
    3、Promise.prototype.then()

    Promise 实例具有 then 方法,也就是说,then 方法是定义在原型对象 Promise.prototype 上的
    then 方法返回的是一个新的 Promise实例(注意,不是原来那个 Promise 实例)。因此可以采用链式写法,即 then 方法后面再调用另一个 then 方法

    getJSON("/posts.json").then(function(json) {
        return json.post;
    }).then(function(post) {
        // ...
    });
    
    上面的代码使用 then 方法,依次指定了两个回调函数。第一个回调函数完成以后,会将返回结果作为参数,传入第二个回调函数
    

    采用链式的 then,可以指定一组按照次序调用的回调函数。这时,前一个回调函数,有可能返回的还是一个 Promise 对象(即有异步操作),这时后一个回调函数,就会等待该 Promise 对象的状态发生变化,才会被调用

    getJSON("/post/1.json").then(function(post) {
        return getJSON(post.commentURL);
    }).then(function (comments) {
        console.log("resolved: ", comments);
    }, function (err){
        console.log("rejected: ", err);
    });
    
    上面代码中,第一个 then 方法指定的回调函数,返回的是另一个 Promise 对象。这时,
    第二个 then 方法指定的回调函数,就会等待这个新的 Promise 对象状态发生变化。
    如果变为 resolved,就调用第一个回调函数,如果状态变为 rejected,就调用第二个回调函数
    
    4、Promise.prototype.catch()

    Promise.prototype.catch() 方法是 .then(null, rejection) 或 .then(undefined, rejection) 的别名,用于指定发生错误时的回调函数

    getJSON('/posts.json').then(function(posts) {
        // ...
    }).catch(function(error) {
        // 处理 getJSON 和 前一个回调函数运行时发生的错误
        console.log('发生错误!', error);
    });
    
    上面代码中,getJSON() 方法返回一个 Promise 对象,如果该对象状态变为 resolved,则会调用 then() 方法指定的回调函数;
    如果异步操作抛出错误,状态就会变为 rejected,就会调用 catch() 方法指定的回调函数,处理这个错误。
    另外,then() 方法指定的回调函数,如果运行中抛出错误,也会被 catch() 方法捕获
    
    p.then((val) => console.log('fulfilled:', val))
        .catch((err) => console.log('rejected', err));
    
    // 等同于
    p.then((val) => console.log('fulfilled:', val))
        .then(null, (err) => console.log("rejected:", err));
    

    一般来说,不要在 then() 方法里面定义 Reject 状态的回调函数(即 then 的第二个参数),总是使用 catch 方法

    // bad
    promise.then(function(data) {
        // success
    }, function(err) {
        // error
    });
    
    // good
    promise.then(function(data) {
        // success
    }).catch(function(err) {
        // error
    });
    
    5、Promise.prototype.finally()

    finally() 方法用于指定不管 Promise 对象最后状态如何,都会执行的操作

    promise
    .then(result => {···})
    .catch(error => {···})
    .finally(() => {···});
    
    上面代码中,不管 promise 最后的状态,在执行完 then 或 catch 指定的回调函数以后,都会执行 finally 方法指定的回调函数
    
    6、Promise.all()

    Promise.all() 方法用于将多个 Promise 实例,包装成一个新的 Promise 实例

    const p = Promise.all([p1, p2, p3]);
    
    只有 p1、p2、p3 的状态都变成 fulfilled,p 的状态才会变成 fulfilled,此时 p1、p2、p3 的返回值组成一个数组,传递给 p 的回调函数
    只要 p1、p2、p3 之中有一个被 rejected,p 的状态就变成 rejected,此时第一个被 reject 的实例的返回值,会传递给 p 的回调函数
    
    7、Promise.race()

    Promise.race() 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例

    const p = Promise.race([p1, p2, p3]);
    
    只要 p1、p2、p3 之中有一个实例率先改变状态,p 的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给 p 的回调函数
    
    8、Promise.allSettled()

    Promise.allSettled() 方法接受一个数组作为参数,数组的每个成员都是一个 Promise 对象,并返回一个新的 Promise 对象

    Promise.allSettled([
        fetch('/api-1'),
        fetch('/api-2'),
        fetch('/api-3'),
    ]);
    
    只有等到参数数组的所有 Promise 对象都发生状态变更(不管是 fulfilled 还是 rejected),返回的 Promise 对象才会发生状态变更
    
    9、Promise.any()
    Promise.any([
        fetch('https://v8.dev/').then(() => 'home'),
        fetch('https://v8.dev/blog').then(() => 'blog'),
        fetch('https://v8.dev/docs').then(() => 'docs')
    ]).then((first) => {  // 只要有一个 fetch() 请求成功
        console.log(first);
    }).catch((error) => { // 所有三个 fetch() 全部请求失败
        console.log(error);
    });
    

    只要参数实例有一个变成 fulfilled 状态,包装实例就会变成 fulfilled 状态;如果所有参数实例都变成 rejected 状态,包装实例就会变成 rejected 状态。

    Promise.any() 跟 Promise.race() 方法很像,只有一点不同,就是 Promise.any() 不会因为某个 Promise 变成rejected 状态而结束,必须等到所有参数 Promise 变成 rejected 状态才会结束

    10、Promise.resolve()
    Promise.resolve('foo')
    // 等价于
    new Promise(resolve => resolve('foo'))
    
    11、Promise.reject()
    Promise.reject('出错了');
    // 等同于
    new Promise((resolve, reject) => reject('出错了'))
    
    12、Promise.try()

    相关文章

      网友评论

          本文标题:ES6 Promise

          本文链接:https://www.haomeiwen.com/subject/elghqdtx.html