Promise的一些相关讲解
在javascrpit的语言特性上 有明确的一个特性指出,该语言的是单线程进程。这就意味着JavaScript的所有网络操作,浏览器事件,都必须是异步执行。
如下面的例子,可以感受到单线程与异步回调:
function callback() {
console.log('Done');
}
console.log('before setTimeout()');
setTimeout(callback, 1000); // 1秒钟后调用callback函数
console.log('after setTimeout()');
将上面代码在控制台打出 我们可以看的到
before setTimeout()
after setTimeout()
(等待1秒后)
Done
可以看出,异步操作 会在未来的某个点 由回调函数触发
再来看一个典型的异步操作:ajax请求
// 这个是原生的ajax请求一部分 注册事件 onreadystatechange 状态改变就会调用
request.onreadystatechange = function () {
if (request.readyState === 4) { //判断服务器是否响应正确
if (request.status === 200) {
return success(request.responseText);
} else {
return fail(request.status);
}
}
}
// 另外 附上原生的ajax请求
//步骤一:创建异步对象
var ajax = new XMLHttpRequest();
//步骤二:设置请求的url参数,参数一是请求的类型,参数二是请求的url,可以带参数,动态的传递参数starName到服务端
ajax.open('get','getStar.php?starName='+name);
//步骤三:发送请求
ajax.send();
//步骤四:注册事件 onreadystatechange 状态改变就会调用
ajax.onreadystatechange = function () {
if (ajax.readyState==4 &&ajax.status==200) {
//步骤五 如果能够进到这个判断 说明 数据 完美的回来了,并且请求的页面是存在的
console.log(ajax.responseText);//输入相应的内容
}
}
对于上面的代码 有些繁琐,可以改写嘛?比如这样
var ajax = ajaxGet('http://...');
ajax.ifSuccess(success)
.ifFail(fail);
上面的代码 体现了一种链式写法,这种写法看起来比较简洁些,并且还体现了另外一个思想:
我不管你有没有请求成功,但是我发起了与服务器的通信,至于结果,我可以再在未来的某个代码片段里去调用 success 与 fail 的函数。
于是 这种 " 承诺于未来将会执行 " 的对象,被称为了promise 中文含义 : 承诺。
promise 有很多的开源实现 在ES6中被统一规范,由浏览器直接支持。可以测试你的浏览器是否支持promise。在控制台上打印以下代码:
new Promise(function () {
console.log('我支持promise')
})
既然知道了promise的大概含义,我们来实现一个这样的例子吧:下面代码里 我们默认当num<1时 是通信成功,不然就是通信失败。模拟一个ajax请求。
function test(success,fail) {
var num = Math.random() * 2;
console.log('相应时间为'+ num +'秒')
setTimeout(function () {
if(num < 1) {
success('执行成功函数');
}else {
fail('执行失败的函数')
}
},num * 1000)
}
能够看出 , test()函数有两个参数,其实就是回调函数,当num < 1时 我们定义其为相应成功,调用success函数,失败时 就调用 fail 函数。由此可以看出:
test()函数只在关心自身的逻辑,并没有去关心 执行success 还是 fail 函数 如何去处理结果。
于是 我们可以用promise对象 来出来这个执行的函数。
var p1 = new Promise(test);
var p2 = p1.then(function (data) {
console.log('成功' + data)
});
var p3 = p2.catch(function (data2) {
console.log('失败' + data2)
})
变量p1是一个Promise对象,它负责执行test函数。由于test函数在内部是异步执行的,当test函数执行成功时,我们告诉Promise对象:
如果执行成功 则执行
p1.then(function (data) {
console.log('成功' + data)
});
失败 则执行:
p2.catch(function (data2) {
console.log('失败' + data2)
})
Promise对象可以串联起来,所以上述代码可以简化为:
new Promise(test).then(function (data) {
console.log('成功:' + data);
}).catch(function (data2) {
console.log('失败:' + data2);
});
继续上面的栗子 看看promise是如何实现异步执行的:
new Promise(function (success, fail) {
console.log('start new Promise...');
var timeOut = Math.random() * 2;
console.log('set timeout to: ' + timeOut + ' seconds.');
setTimeout(function () {
if (timeOut < 1) {
console.log('执行成功函数');
success('200 OK');
}
else {
console.log('执行失败函数');
fail('timeout in ' + timeOut + ' seconds.');
}
}, timeOut * 1000);
}).then(function (r) {
console.log('Done: ' + r);
}).catch(function (reason) {
console.log('Failed: ' + reason);
});
可以将上面的代码打入控制台 你可以看到类如下面的结果

可见Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了
此时 我们再看一个axios的请求 axios支持promise API
axios.get('/user?ID=12345')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
怎么样 形式上 是不是就会感觉到 一种很熟悉的,这样也就能理解 axios请求的写法了。
Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。
要串行执行这样的异步任务,不用Promise需要写一层一层的嵌套代码。有了Promise,我们只需要简单地写:
job1.then(job2).then(job3).catch(handleError);
下面有个具体的例子说明:
// 0.5秒后返回input*input的计算结果:
function multiply(input) {
return new Promise(function (resolve, reject) {
console.log('计算 ' + input + ' x ' + input + '...');
setTimeout(resolve, 500, input * input);
});
} // 0.5秒后返回input+input的计算结果:
function add(input) {
return new Promise(function (resolve, reject) {
console.log('计算 ' + input + ' + ' + input + '...');
setTimeout(resolve, 500, input + input);
});
} var p = new Promise(function (resolve, reject) {
console.log('开始promise');
resolve(123);
}); p.then(multiply)
.then(add)
.then(multiply)
.then(add)
.then(function (result) {
console.log('最后的结果 ' + result);
});
在控制台打出上面的代码 可以看到;

我们可以再看一下 vuejs 官方提供的与服务器通信的插件 axios 的大概实现原理。这里是基于原生ajax请求改写
function ajax(method,url,params) {
var request = new XMLHttpRequest();
return new Promise(function (success,fail) {
request.onreadystatechange = function () {
if(request.readyState === 4 && request.status === 200) {
success(request.responseText);
}else {
fail(request.status)
}
}
request.open(method,url);
request.send(params)
})
}
紧接着 我们的调用
var p = ajax('GET', '/api',params);
p.then(function (text) { // 如果AJAX成功,获得响应内容
console.log(text)
}).catch(function (status) { // 如果AJAX失败,获得响应代码
lconsole.log(status);
});
另外:
promise.all()方法,可以支持并行异步操作
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, '第一个');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, '第二个');
});
// 同时执行p1和p2,并在它们都完成后执行then:
Promise.all([p1, p2]).then(function (results) {
console.log(results); // 获得一个Array: ['第一个', '第二个']
});
Promise.race()方法,可以实现两个异步请求,有一个先返回即可
var p1 = new Promise(function (resolve, reject) {
setTimeout(resolve, 500, '第一个');
});
var p2 = new Promise(function (resolve, reject) {
setTimeout(resolve, 600, '第二个');
});
// 同时执行p1和p2,并在它们都完成后执行then:
Promise.race([p1, p2]).then(function (results) {
console.log(results); // 输出第一个 第二个会被默认丢弃
});
由于p1运行较快,所以promise的then 会获得 ‘第一个’的输出。第二个会被默认丢弃。
综上:
如果我们组合使用Promise,就可以把很多异步任务以并行和串行的方式组合起来执行
Promise的一些相关讲解的更多相关文章
- JWT的相关讲解
原文链接: http://www.cnblogs.com/chenwolong/p/Token.html
- 关于git rebase的相关讲解
http://gitbook.liuhui998.com/4_2.html 一.基本 git rebase用于把一个分支的修改合并到当前分支. 假设你现在基于远程分支"origin" ...
- 关于html的相关讲解
浏览器chrome Chrome它内部有一个解析器,这个解析器就是解析我们的代码,各个浏览器的内核不一样,所以存在浏览器的兼容.这个内核是一个引擎. 谷歌的内核是webkit 引擎是v8. 客户端的请 ...
- Promise原理讲解 && 实现一个Promise对象 (遵循Promise/A+规范)
1.什么是Promise? Promise是JS异步编程中的重要概念,异步抽象处理对象,是目前比较流行Javascript异步编程解决方案之一 2.对于几种常见异步编程方案 回调函数 事件监听 发布/ ...
- 【Mocha.js 101】同步、异步与 Promise
前情提要 在上一篇文章<[Mocha.js 101]Mocha 入门指南>中,我们提到了如何用 Mocha.js 进行前端自动化测试,并做了几个简单的例子来体验 Mocha.js 给我们带 ...
- 浅谈Promise
学习过JavaScript的人都知道,JavaScript是单线程作业,这样会有一个很大的缺陷,所有的Ajax,浏览器事件等,都是通过异步去完成.所谓的同步和异步最大的区别无非就是在于同步会阻塞后续代 ...
- 分步理解 Promise 的实现
一个 Promise 的运用: var firstPromise = new Promise(function(resolve,reject){ setTimeout(function(){ var ...
- ES6入门八:Promise异步编程与模拟实现源码
Promise的基本使用入门: ——实例化promise对象与注册回调 ——宏任务与微任务的执行顺序 ——then方法的链式调用与抛出错误(throw new Error) ——链式调用的返回值与传值 ...
- promise 进阶 —— async / await 结合 bluebird
一.背景 1.Node.js 异步控制 在之前写的 callback vs async.js vs promise vs async / await 里,我介绍了 ES6 的 promise 和 ES ...
随机推荐
- 1012: [JSOI2008]最大数maxnumber 线段树
https://www.lydsy.com/JudgeOnline/problem.php?id=1012 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数 ...
- MongoDB 3.4 分片集群副本集 认证
连接到router所在的MongoDB Shell 我本机端口设置在50000上 mongo --port 接下来的流程和普通数据库添加用户权限一样 db.createUser({user:&quo ...
- UVA-1611 Crane (构造)
题目大意:给一个1~n的序列,每次操作可以把长度为偶数的序列交换前一半和后一半的位置.求出将这个序列变成升序的步骤. 题目分析:构造求解. 代码如下: # include<iostream> ...
- ansible入门六(roles)
一.什么场景下会用roles? 假如我们现在有3个被管理主机,第一个要配置成httpd,第二个要配置成php服务器,第三个要配置成MySQL服务器.我们如何来定义playbook? 第一个play用到 ...
- js点击复制功能的实现
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- MVC DateTime 字段 EditTime 必须是日期模板只能用于字段访问、属性访问、一维数组索引或单参数自定义索引器表达式
ASP.NET MVC 中model含有DateTime类型的字段 更新字段时提示:字段 EditTime必须是日期,. 但是明明填入的是日期还是给出这个提示, 看有的博客说那是因为日期形式错了,如果 ...
- TCP三次握手,四次挥手,状态变迁图
body, table{font-family: 微软雅黑; font-size: 13.5pt} table{border-collapse: collapse; border: solid gra ...
- Python中的数据结构 --- 元组(tuple)、字典(tuple)
元组(tuple)本身是不可变数据类型,没有增删改查:元组内可以存储任意数据类型一.元组的创建 例:t = (1,2.3,'star',[1,2,3]) ## 元组里面包含可变类型,故 ...
- Linux:tee命令详解
tee tee命令用于将数据重定向到文件,另一方面还可以提供一份重定向数据的副本作为后续命令的stdin,简单的说就是把数据重定向到给定文件和屏幕上. 语法 tee(选项)(参数) 选项 -a:向文件 ...
- HAWQ + MADlib 玩转数据挖掘之(五)——奇异值分解实现推荐算法
一.奇异值分解简介 奇异值分解简称SVD(singular value decomposition),可以理解为:将一个比较复杂的矩阵用更小更简单的三个子矩阵的相乘来表示,这三个小矩阵描述了大矩阵重要 ...