浅析Promise

在JavaScript当中 , 不存在真正的多线程 , 从而导致所有需要异步执行的操作都需要使用回调函数实现

例如 : 使用定时器去执行一个回调函数

function callback(){
    console.debug("Time Out!");
}
console.log("before");
setTimeout(callback,1000);
console.log("after");
 

定时器会在1秒之后去执行callback这个回调函数
这就实现了一个简单的异步操作
异步操作会在将来的某个时间点触发一个函数调用
Ajax的异步请求也是一种异步操作

类似这种承诺将来会执行的对象 , 在ES6当中被统一规范为Promise对象

这个对象的最大作用就是将执行代码和处理结果的回调函数进行了分离 , 从而在存在多重回调的情境当中 , 代码的可读性更强

一个简单的例子

var status = true;
function test(resolve, reject) {
    if (status) {
        resolve(‘success‘);
    } else {
        reject(‘failed‘);
    }
}
var p1 = new Promise(test);
//then传入的是resolve的实现
//catch传入的是reject的实现
p1.then(console.log).catch(console.error);
/*
也可以用如下的方式, 实际效果同上
p1.then(console.log, console.log);
*/

Promise对象在创建的时候 , 传入的这个函数当中并不关心成功与失败具体的回调是什么 , 而只是关心何时去执行该回调函数

Promise对象有3种状态

  1. Fulfilled 成功的状态
  2. Rejected 失败的状态
  3. Pending Promise 对象实例创建时候的初始状态

可以由初始状态转换到成功状态 , 或者由初始状态转换到失败状态 , 并且不可逆
我们可以在初始化函数里面自己编写逻辑来确定何种情况下执行成功的回调函数( resolve ) 或者失败的函数( reject )
如果抛出错误而且没有进行捕获 , 则一定会执行失败的函数( reject )

如果对于某种状态 , 要执行多个回调函数
可以进行链式调用 , 也就是连缀多个then方法
前一个then方法中的返回值会作为下一个回调函数的参数

var status = true;
function test(resolve, reject) {
    if (status) {
        resolve(‘success‘);
    } else {
        reject(‘failed‘);
    }
}
var p1 = new Promise(test);
p1
.then(function(msg){
    console.log("我是第一个回调函数:" + msg);
    return msg;
})
.then(function(msg){
    console.log("我是第二个回调函数:" + msg);
})
.catch(console.error);

当然上面这种方式只能适用于多重回调函数中只有一个参数的情况
如果要传多个参数
必须使用数组的形式传递
比如参数中是function([msg1, msg2])
前一个回调函数中return ["AA","BB"]


Promise.all 和 Promise.race

Promise.all方法可以接收一个Promise对象构成的数组作为参数 , 返回一个Promise对象
当数组中的这些Promise对象全部转换为成功状态的时候 , 这个对象才转换为成功状态 , 否则就转换为失败状态

var status = [true, true];
function test1(resolve, reject){
    if(status[0]) {
        resolve("success");
    } else {
        reject("failed");
    }
}
function test2(resolve, reject){
    if(status[1]) {
        resolve("success");
    } else {
        reject("failed");
    }
}
var p1 = new Promise(test1);
var p2 = new Promise(test2);
p1.then((msg)=>console.log("成功" + msg))
.catch((msg)=>console.error("失败" + msg));

p2.then((msg)=>console.log("成功" + msg))
.catch((msg)=>console.error("失败" + msg));

Promise.all([p1,p2])
.then(function(msgs){
    console.log(msgs instanceof Array);//true
    console.log(msgs);//[ ‘success‘, ‘success‘ ]
});
//注意 : 这里的回调函数的参数就是所有Promise对象成功回调函数传入参数的数组
//(如果只有一个参数,则不构成数组)

Promise.race方法的用法与all类似 , 它返回的Promise对象是当数组中存在Promise对象转为成功状态的时候 , 它就转为成功状态 , 如果全是失败状态 , 它才是失败状态

status[1] = false;
var p3 = new Promise(test1);
var p4 = new Promise(test2);
p3.then((msg)=>console.log("成功" + msg))
.catch((msg)=>console.error("失败" + msg));

p4.then((msg)=>console.log("成功" + msg))
.catch((msg)=>console.error("失败" + msg));
Promise.race([p3,p4])
.then(function(msgs){
    //参数规则同Promise.all
    console.log(msgs);
});

如果只是执行一次单步回调 , 那么传统的回调函数执行的方式其实并没有什么问题

Promise的主要意义是在于解决多重回调的多层嵌套问题
如果回调的嵌套层级太多 , 会造成代码可读性很差 , 难以维护
例如

var test = function(num, func) {
    console.log(num);
    func(num);
};
test(1, function(a){
    test(2, function(b){
        test(3, function(c){
            console.log("回调成功");
        });
    });
});

使用Promise可以将上述的代码改造成线性的模式 , 可读性增强 , 同时也更便于调试

var pro = new Promise(function(resolve, reject){
    resolve(1);
}).then(function(val){
    console.log(val);
    return new Promise(function(resolve, reject){
        resolve(2);
    });
}).then(function(val){
    console.log(val);
    return new Promise(function(resolve, reject){
        resolve(3);
    });
}).then(function(val){
    console.log(val);
});

让then方法的函数每次都是返回不同的Promise实例 , 再去指定这个实例的回调函数即可

并且对于Promise对象 , 它的回调执行是异步的
例如 :

new Promise(function(resolve, reject){
    resolve("AA");
}).then(function(msg){
    console.log(msg);
});
console.log("BB");
/* output:
BB
AA
*/

对于异步操作实现的原理 , 可以参考JS的事件驱动模型
JS引擎会将回调函数的执行加入到事件队列当中
从而实现在单线程的条件下 , 代码的异步执行

 
时间: 2024-12-20 14:48:11

浅析Promise的相关文章

关于 requestAnimationFrame 小结

一.小谈 requestAnimationFrame: 说起 requestAnimationFrame,我们先看幅图: 相当一部分的浏览器的显示频率是16.7ms, 就是上图第一行的节奏,表现就是“我和你一步两步三步四步往前走……”.如果我们火力搞猛一点,例如搞个10ms setTimeout,就会是下面一行的模样——每第三个图形都无法绘制(红色箭头指示),表现就是“我和你一步两步 坑四步往前走……”. 想象国庆北京高速,最多每16.7s通过一辆车,结果,突然插入一批 setTimeout的军

延期(deferred)的承诺(promise) —— jq异步编程浅析

引子 相信各位developers对js中的异步概念不会陌生,异步操作后的逻辑由回调函数来执行,回调函数(callback function)顾名思义就是“回头调用的函数”,函数体事先已定义好,在未来的某个时候由某个事件触发调用,而这个时机,是程序本身无法控制的. 举几个常见例子: 事件绑定 动画 Ajax 上面的例子简单.典型,易于阅读和理解. 为了引出本文的主题,假设现在有3个ajax异步操作,分别为A.B.C,每个都封装成了函数,并可传入success回调作为参数. 请考虑以下场景: 希望

Jquery中的异步编程浅析 延期(deferred)的承诺(promise)

引子 相信各位developers对js中的异步概念不会陌生,异步操作后的逻辑由回调函数来执行,回调函数(callback function)顾名思义就是"回头调用的函数",函数体事先已定义好,在未来的某个时候由某个事件触发调用,而这个时机,是程序本身无法控制的. 举几个常见例子: 事件绑定 动画 Ajax 上面的例子简单.典型,易于阅读和理解. 为了引出本文的主题,假设现在有3个ajax异步操作,分别为A.B.C,每个都封装成了函数,并可传入success回调作为参数. 请考虑以下场

Ajax语法浅析

Ajax是目前很普遍的一门技术,也是很值得探讨和研究的一门技术.本文将针对Ajax的发展过程并结合其在不同库框架中的使用方式来和大家分享下Ajax的那些新老语法. Ajax语法浅析 Ajax简介 Ajax全称为"Asynchronous Javascript And XML",即"异步JavaScript和XML"的意思.通过Ajax我们可以向服务器发送请求,在不阻塞页面的情况下进行数据交互,也可以理解为异步数据传输.在Ajax的帮助下我们的网页只需局部刷新即可更新

jQuery 3.0 的 Data 浅析

jQuery 3.0 在6月9日正式发布了,3.0 也被称为下一代的 jQuery .这个版本从14年10月开始,其中发布过一次beta 版(2016/1/14,)和候选版(2016/05/20).一路走来,颇为不易. 文章目录 Data浅析 Data在jQuery内部的使用 1.x.x 和 2.x.x 的比较 一.Data浅析 jQuery 3.0 中的 Data 是内部使用的,定义为一个“类”.一共用它创建了两个对象,dataPriv 和 dataUser.Data 有 1 个对象属性(ex

React Native Android 源码框架浅析(主流程及 Java 与 JS 双边通信)

[工匠若水 http://blog.csdn.net/yanbober 未经允许严禁转载,请尊重作者劳动成果.私信联系我] 1 背景 有了前面<React Native Android 从学车到补胎和成功发车经历>和<React Native Android Gradle 编译流程浅析>两篇文章的学习我们 React Native 已经能够基本接入处理一些事情了,那接下来的事情就是渐渐理解 RN 框架的一些东西,以便裁剪和对 RN 有个更深入的认识,所以本篇总结了我这段时间阅读源码

[JavaScript]MVC浅析

MVC浅析 MVC或多或少都有听说过,我知道如果要作为一个前端的话,MVC应该是一个显示技术水平的槛,是绕不过去的,所以我乖乖来写这篇文章,对MVC进行一些粗浅的分析和归纳,以加深对MVC的理解. MVC是一种代码组织形式,他把代码依据功能的不同划分成三个部分,分别是Model.Controller.View. View代表视图,Model代表对数据的操作(存储和获取等),Controller代表了View和Model两者之间的交互逻辑以及其他. 他们之间的相互作用是这样的:用户对View视图做

切图崽的自我修养-[ES6] 异步函数管理方案浅析

前言 业务开发中经常会用到异步函数,这里简单的对异步函数以及它的各种各样的解决方案做一个浅析 优缺点: 优点: 能够极大的提高程序并发业务逻辑的能力. 缺点: 异步函数的书写方式和代码执行逻辑很不直观,回调函数这种方式不太符合人类的的线性思维 异步函数的执行流程通常不好管理 不好对异步函数部署错误处理机制 解决方案 针对异步函数存在的缺点,所以才有了形形色色的异步的处理方案,常见的比如 原生的回调函数 promise/A+ async/await(generator); 业务场景 但这些解决方案

Python之encode与decode浅析

 Python之encode与decode浅析 在 python 源代码文件中,如果你有用到非ASCII字符,则需要在文件头部进行字符编码的声明,声明如下: # code: UTF-8 因为python 只检查 #.coding 和编码字符串,为了美观等原因可以如下写法: #-*-coding:utf-8-*- 常见编码介绍: GB2312编码:适用于汉字处理.汉字通信等系统之间的信息交换. GBK编码:是汉字编码标准之一,是在 GB2312-80 标准基础上的内码扩展规范,使用了双字节编码.