首页技术文章正文

promise解析【黑马web前端】

更新时间:2019年07月26日 10时52分59秒 来源:黑马程序员论坛

什么是PromisePromise 是异步编程的一种解决方案,比传统的异步解决方案【回调函数】和【事件】更合理、更强大。
  • 从语法上讲,promise 是一个对象,从它可以获取异步操作的消息
  • 从本意上讲,它是承诺,承诺它过一段时间会给你一个结果
代码书写比较首先封装一个支持 Promise 的 ajax 方法,不理解这块代码的话,也没有关系,后文会逐步讲解 Promise 的执行机制

function request(url,data = {}){
    return new Promise((resolve,reject)=>{
        $.ajax({
            url,
            data,
            success:function (data) {
                resolve(data);
            },
            error:function (error) {
                reject(error);
            }
        })
    });
}

用 request 方法实现前面多个互相依赖的网络请求
let url1 = 'http://xxx.xxx.1';
let url2 = 'http://xxx.xxx.2';
let url3 = 'http://xxx.xxx.3';
request(url1)
    .then((data)=>{
        console.log(data);
        return request(url2,data)
    })
    .then((data)=>{
        console.log(data);
        return request(url3,data)
    })
    .then((data)=>{
        console.log(data)
    })
    .catch((error)=>{
        console.log(error);
    });

Promise 的特性promise 的状态
  • pending   (等待态)
  • fulfilled (完成态)
  • rejected  (拒绝态)
终值与拒因
  • 终值:指的是 promise 被解决时传递给解决回调的值
  • 拒因:拒绝原因,指在 promise 被拒绝时传递给异常回调的拒绝原因
状态与状态关系,状态与终值和拒因的关系
  • pending 可以迁移至 fulfilled 或 rejected
  • fulfilled 不能迁移至其他状态,必须拥有一个不可变的终值
  • rejected 不能迁移至其他状态,必须拥有一个不可变的据因
Promise 的使用构造函数Promise 是一个构造函数,使用 new 操作符返回一个 promise 对象
构造函数接收一个 excutor 函数作为参数
excutor 函数有两个函数类型的参数 resolve 和 reject
let p = new Promise((resolve,reject)=>{     // 在 excutor 函数中执行异步操作     // 当异步操作完成后,调用 resolve 函数或 reject 函数});
  • 构造函数在调用时,excutor 函数会作为同步代码立即执行
  • 我们通常在 excutor 函数中执行我们的异步操作
  • 未调用 resolve、reject 函数时,promise 对象的状态为 pending
let p1 = new Promise((resolve,reject)=>{    setTimeout(()=>{        console.log('p1');    },1000);});// p1 的状态一直为 pending
  • 当调用 resolve 函数, resolve 的参数为非 promise 对象、非 thenable 对象
    • resolve 函数的参数,作为 promise 对象的终值
    • promise 对象的状态变为 fulfilled
let p2 = new Promise((resolve,reject)=>{    setTimeout(()=>{        console.log('p2');        resolve('我是p2的终值')    },1000);});// 代码执行,1000ms内,p2 的状态为 pending// 代码执行,1000ms后,p2 的状态为 fulfilled// 代码执行,1000ms后,p2 的终值为 '我是p2的终值'
  • 当调用 resolve 函数, resolve 的参数为 promise 对象
    • promise 对象的状态、终值、拒因与传入的 promise 对象同步
let p = new Promise((resolve,reject)=>{    reject('error')})let p1 = new Promise((resolve,reject)=>{    resolve(p)})// p1 的状态为 rejected ,拒因为 error
  • 当调用 resolve 函数, resolve 的参数为 thenable 对象
    • 会对 thenable 对象进行展开操作,promise 对象的状态、终值、拒因取决于 thenable 对象的 then 方法调用结果
let thenable1 = {    then:function(resolve,reject){        resolve(1)    }}let thenable2 = {    then:function(resolve,reject){        reject(2)    }}let thenable3 = {    then:function(resolve,reject){        throw new Error(3)    }}let thenable4 = {    then:function(fn1,fn2){        //不调用 fn1 fn2    }}let p1 = new Promise((resolve,reject)=>{    resolve(thenable1);})let p2 = new Promise((resolve,reject)=>{    resolve(thenable2);})let p3 = new Promise((resolve,reject)=>{    resolve(thenable3);})let p4 = new Promise((resolve,reject)=>{    resolve(thenable4);})// p1 的状态为 fulfilled 终值为 1// p2 的状态为 rejected  终值为 2// p3 的状态为 rejected  拒因为 Error:3// p4 的状态为 pending
  • 当调用 reject 函数, reject 函数的参数,作为 promise 对象的拒因
  • promise 对象的状态变为 rejected
let p3 = new Promise((resolve,reject)=>{    setTimeout(()=>{        console.log('p3');        reject('我是p3的拒因')    },1000);});// 代码执行,1000ms内,p3 的状态为 pending// 代码执行,1000ms后,p3 的状态为 rejected// 代码执行,1000ms后,p3 的拒因为 '我是p3的拒因'
promise对象上的方法then方法:promise 提供一个 then 方法,用于访问其终值和拒因。
promise 的 then 方法接受两个参数:
promise.then(onFulfilled, onRejected);
  • onFulfilled 函数用于当 promise 状态变为 fulfilled 时,接收终值
  • onRejected 函数用于当 promise 状态变为 rejected 时,接收拒因
new Promise((resolve,reject)=>{    setTimeout(()=>{        resolve('异步任务获取的数据')    },50)}).then((data)=>{    console.log(data)})// 异步任务获取的数据
new Promise((resolve,reject)=>{    setTimeout(()=>{        reject(new Error('异步任务异常'))    },50)}).then(null,(error)=>{    console.log(error)})// Error: 异步任务异常
new Promise((resolve,reject)=>{    throw new Error('抛出一个异常');}).then(null,(error)=>{    console.log(error)})// Error: 抛出一个异常
onFulfilled 和 onRejected 参数可选
  • 如果 onFulfilled 不是函数,其必须被忽略
  • 如果 onRejected 不是函数,其必须被忽略
onFulfilled 特性如果 onFulfilled 是函数:
  • 当 promise 执行结束后其必须被调用,其第一个参数为 promise 的终值
  • 在 promise 执行结束前其不可被调用
  • 其调用次数不可超过一次
onRejected 特性如果 onRejected 是函数:
  • 当 promise 被拒绝执行后其必须被调用,其第一个参数为 promise 的据因
  • 在 promise 被拒绝执行前其不可被调用
  • 其调用次数不可超过一次
onFulfilled 和 onRejected 的调用时机
  • 当 promise 对象的状态变为 fulfilled 或 rejected 时调用
  • onFulfilled、onRejected 永远都是异步调用
  • onFulfilled、onRejected 在事件队列中作为微任务来处理
console.log(1);setTimeout(function(){    console.log(2)},0)new Promise((resolve,reject)=>{    resolve(3);}).then((data)=>{    console.log(data);})console.log(4)// print: 1 4 3 2
onFulfilled 和 onRejected 的调用要求
  • onFulfilled 和 onRejected 必须被作为函数调用
  • 非严格模式下,this 为全局对象
  • 严格模式下,this 为 undefined
function fn1(){    new Promise((resolve)=>{        resolve();    }).then(function(){        console.log(this)    })}function fn2(){    "use strict";    new Promise((resolve)=>{        resolve();    }).then(function(){        console.log(this)    })}fn1(); // print: windowfn2(); // print: undefined
then方法的多次调用
  • then 方法可以被同一个 promise 对象多次调用
  • then 方法会返回一个新的 promise 对象
  • 当 promise 成功执行时,所有 onFulfilled 需按照其注册顺序依次回调
  • 当 promise 被拒绝执行时,所有的 onRejected 需按照其注册顺序依次回调
let p = new Promise((resolve)=>{    resolve()});let p1 = p.then(()=>{    console.log('异步执行,第一个onFulfilled');});let p2 = p.then(()=>{    console.log('异步执行,第二个onFulfilled');});console.log(p1.constructor === Promise);console.log(p === p1);console.log(p === p2);console.log(p1 === p2);// print: true// print: false// print: false// print: false// print: 异步执行,第一个onFulfilled// print: 异步执行,第二个onFulfilled
then方法的返回值then 方法返回一个 promise 对象
promise2 = promise1.then(onFulfilled, onRejected);   
  • 若 onFulfilled 、onRejected 返回一个非promise对象、非thenable对象的值 x ,则 promise2 的状态为 fulfilled ,终值为 x
let p = new Promise((resolve,reject)=>{    throw new Error();});let p1 = p.then(null,(data)=>{    return '我是p2的终值'});p1.then((data)=>{    console.log(data)});// print: 我是p2的终值
  • 若 onFulfilled 、onRejected 返回一个 promise 对象的值 x ,promise2 的状态、终值、拒因与 x 同步
let p1 = new Promise((resolve,reject)=>{    resolve(1)})let p2 = new Promise((resolve,reject)=>{    reject(2)})let p3 = new Promise((resolve)=>{    resolve()})let p4 = p3.then(()=>{    return p1;})let p5 = p3.then(()=>{    return p2;})// p4 的状态为 fulfilled 终值为 1// p5 的状态为 rejected  拒因为 2
  • 若 onFulfilled 、onRejected 返回一个 thenable 对象 ,会对 thenable 对象进行展开操作,promise2 的状态、终值、拒因取决于 thenable 对象的 then 方法调用结果
let thenable1 = {    then:function(resolve,reject){        resolve(1)    }}let thenable2 = {    then:function(resolve,reject){        reject(2)    }}let p1 = new Promise((resolve,reject)=>{    resolve()})let p2 = p1.then(()=>{    return thenable1;})let p3 = p1.then(()=>{    return thenable2;})// p2 的状态为 fulfilled 终值为 1// p3 的状态为 rejected  拒因为 2
  • 若 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 的状态为 rejected,拒因为 e
let p = new Promise((resolve,reject)=>{    resolve();});let p1 = p.then((data)=>{    throw new Error('error')});p1.then(null,(err)=>{    console.log(err);});// print: Error: error
  • 若 onFulfilled 不是函数且 promise1 成功执行, promise2 的状态为 fulfilled 终值为 promise1 的终值
let p = new Promise((resolve,reject)=>{    resolve('我是p1的终值');});let p1 = p.then(null,null);p1.then((data)=>{    console.log(data);});// print: 我是p1的终值
  • 若 onRejected 不是函数且 promise1 拒绝执行, promise2 的状态为 rejected 拒因为 promise1 的拒因
let p = new Promise((resolve,reject)=>{    reject('我是p1的拒因');});let p1 = p.then(null,null);p1.then(null,(err)=>{    console.log(err);});// print:我是p1的拒因
  • 若 onFulfilled、onRejected 执行过程中抛出异常,则 promise2 的状态为 rejected 拒因为抛出的异常
let p = new Promise((resolve,reject)=>{    resolve('我是p的终值');});let p1 = p.then((data)=>{    throw new Error('异常')});p1.then(null,(err)=>{    console.log(err);});// print:Error: 异常
终值和拒因的穿透特性
  • 如果 promise 的状态变为 fulfilled,then 方法没有注册 onFulfilled
    • then 方法返回的 promise 对象的状态变为 fulfilled
    • then 方法返回的 promise 对象的终值与原 promise 对象的终值相同
  • 如果 promise 的状态变为 rejected,then 方法没有注册 onRejected
    • then 方法返回的 promise 对象的状态变为 rejected
    • then 方法返回的 promise 对象的拒因与原 promise 对象的拒因相同
let p1 = new Promise((resolve,reject)=>{    resolve(1)})let p2 = new Promise((resolve,reject)=>{    reject(2)})let p3 = p1.then(null,null);let p4 = p2.then(null,null);// p3 的状态是 fulfilled 终值 1// p4 的状态是 rejected  拒因 2p5 = p3.then(null,null);p6 = p4.then(null,null);// p3 的状态是 fulfilled 终值 1// p4 的状态是 rejected  拒因 2
  • 穿透特性主要用于异常处理
let fn1 = function(){}let fn2 = function(){}let fn3 = function(){}let fn4 = function(){}let fn5 = function(){}let onError = function(){};new Promise((resolve,reject)=>{    setTimeout(function(){        reject()    })}).then(fn1).then(fn2).then(fn3).then(fn4).then(fn5).then(null,onError)
fn1、fn2、fn3、fn4、fn5 都可能发生错误,通过在最后的then函数注册的 onRejected 函数接收可能发生异常错误
catch方法:catch(fn) 方法实际上是 then(null,fn) 方法的别名,catch 方法的返回值以及 catch 方法中出现异常的情况与调用 then 方法相同
new Promise((resolve,reject)=>{    reject()}).then(null,function(error){})// 等同于new Promise((resolve,reject)=>{    reject()}).catch(function(error){})
Promise 的静态方法Promise.resolve
  • Promise.resolve 方法用于将现有数据转换为 promise 对象
    • 若入参为 promise 对象
      • 返回的 promise 对象的状态、终值、拒因与 Promise.resolve 方法的入参同步
    • 若入参为 thenable 对象
      • 会对 thenable 对象进行展开操作,返回的 promise 对象的状态、终值、拒因取决于 thenable 对象的 then 方法调用结果
    • 若入参为非 promise 非 thenable 对象
      • 返回的 promise 对象的状态为 fulfilled
      • 返回的 promise 对象的终值为 Promise.resolve 方法的入参
let p = Promise.resolve(x)// 等价于let p = new Promise((resolve)=>{    resolve(x)})
Promise.reject
  • Promise.reject 方法用于返回一个状态为 rejected ,拒因为方法入参的 promise 对象
let p = Promise.reject(x)// 等价于let p = new Promise((resolve,reject)=>{    reject(x)})
Promise.all
  • Promise.all 方法用于将多个 promise 对象包装成一个新的 promise 对象
const p = Promise.all([p1, p2, p3]);
  • p1、p2、p3 都是 promise 对象,如果不是,调用 Promise.resolve 方法转换为 promise 对象
  • p 的状态由 p1、p2、p3 决定
    • 当 p1、p2、p3 的状态都变成 fulfilled
      • p 的状态为 fulfilled
      • 此时 p1、p2、p3 的终值组成一个数组,这个数组作为 p 的终值
    • 当 p1、p2、p3 的状态有一个变成 rejected
      • p 的状态变为 rejected
      • 此时第一个状态变为 rejected 的 promise 对象的拒因作为 p 的拒因
let p1 = Promise.resolve(1);let p2 = Promise.resolve(2);let p3 = 3;Promise.all([p1,p2,p3]).then((data)=>{    console.log(data); // print: [1,2,3]})
let p1 = Promise.resolve(1);let p2 = new Promise((resolve,reject)=>{    setTimeout(function(){        reject('p2 error')    },1000)})let p3 = new Promise((resolve,reject)=>{    setTimeout(function(){        reject('p3 error')    },500)})Promise.all([p1,p2,p3]).catch((error)=>{    console.log(error); // print: p3 error})
Promise.race
  • Promise.race 方法同样用于将多个 promise 对象包装成一个新的 promise 对象
const p = Promise.race([p1, p2, p3]);
  • p1、p2、p3 都是 promise 对象,如果不是,调用 Promise.resolve 方法转换为 promise 对象
  • p 的状态由 p1、p2、p3 中状态最先变为 fulfilled 或 rejected 的 promise 对象决定
  • p 的终值或拒因由最先变更状态的 promise 对象所决定
let p1 = Promise.resolve(1);let p2 = new Promise((resolve,reject)=>{    setTimeout(function(){        reject('p2 error')    },1000)})let p3 = new Promise((resolve,reject)=>{    setTimeout(function(){        reject('p3 error')    },500)})Promise.race([p1,p2,p3]).then(data=>{    console.log(data);}).catch(error=>{    console.log(error);})// print: 1
let p1 = new Promise((resolve,reject)=>{    setTimeout(function(){        resolve(1)    },1000)})let p2 = new Promise((resolve,reject)=>{    setTimeout(function(){        reject('p2 error')    },800)})let p3 = new Promise((resolve,reject)=>{    setTimeout(function(){        reject('p3 error')    },500)})Promise.race([p1,p2,p3]).then(data=>{    console.log(data);}).catch(error=>{    console.log(error);})// print: p3 error
Promise 的错误捕获当 promise 的状态为 rejected 且为对 promise 对象使用 catch 方法,此时的异常信息会被 promise 对象吃掉可以通过监听 unhandledRejection 事件,专门监听未捕获的reject错误
// node 环境下process.on('unhandledRejection', error => {    console.log('unhandledRejection', error);});// 浏览器下window.addEventListener('unhandledrejection',(e)=>{    e.preventDefault();    console.log(e);});




推荐了解热门学科

java培训 Python人工智能 Web前端培训 PHP培训
区块链培训 影视制作培训 C++培训 产品经理培训
UI设计培训 新媒体培训 产品经理培训 Linux运维
大数据培训 智能机器人软件开发




传智播客是一家致力于培养高素质软件开发人才的科技公司“黑马程序员”是传智播客旗下高端IT教育品牌。自“黑马程序员”成立以来,教学研发团队一直致力于打造精品课程资源,不断在产、学、研3个层面创新自己的执教理念与教学方针,并集中“黑马程序员”的优势力量,针对性地出版了计算机系列教材50多册,制作教学视频数+套,发表各类技术文章数百篇。

传智播客从未停止思考

传智播客副总裁毕向东在2019IT培训行业变革大会提到,“传智播客意识到企业的用人需求已经从初级程序员升级到中高级程序员,具备多领域、多行业项目经验的人才成为企业用人的首选。”

中级程序员和初级程序员的差别在哪里?
项目经验。毕向东表示,“中级程序员和初级程序员最大的差别在于中级程序员比初级程序员多了三四年的工作经验,从而多出了更多的项目经验。“为此,传智播客研究院引进曾在知名IT企业如阿里、IBM就职的高级技术专家,集中研发面向中高级程序员的课程,用以满足企业用人需求,尽快补全IT行业所需的人才缺口。

何为中高级程序员课程?

传智播客进行了定义。中高级程序员课程,是在当前主流的初级程序员课程的基础上,增加多领域多行业的含金量项目,从技术的广度和深度上进行拓展“我们希望用5年的时间,打造上百个高含金量的项目,覆盖主流的32个行业。”传智播客课程研发总监于洋表示。




黑马程序员热门视频教程【点击播放】

Python入门教程完整版(懂中文就能学会) 零起点打开Java世界的大门
C++| 匠心之作 从0到1入门学编程 PHP|零基础入门开发者编程核心技术
Web前端入门教程_Web前端html+css+JavaScript 软件测试入门到精通


在线咨询 我要报名
和我们在线交谈!