理解Promise
一、Propmise基本用法
Promise用于发送一个异步完成的结果,是替代回调函数的另一种选择。可以把Promise理解为一种异步函数。
以下函数通过一个Promise来异步地返回一个结果
function asyncFunc() {
return new Promise(
function (resolve, reject) {
···
resolve(result);
···
reject(error);
});
}
你可以这样调用它:
asyncFunc()
.then(result => { ··· })
.catch(error => { ··· });
NOTE
promise正常情况下结果只能用.then(result =>)来获取。
特殊情况下,在co工具中,使用yield可以得到Promise的结果。
1. Chaining then() calls(链式调用then)
then() 总是返回一个Promise,这使得你可以链式调用:
asyncFunc1()//----设该函数会得到一个promise P,它会resolve出来result1
.then(result1 => {
// Use result1
return asyncFunction2(); // 得到一个promise A, 它会resolve出来result2
})
.then(result2 => { //
// Use result2
})
.catch(error => {
// Handle errors of asyncFunc1() and asyncFunc2()
});
Promise P在.then()之后返回了什么东西取决于then中的函数做了什么:
- 如果then()中的函数返回的是一个Promise(如A), 则这个 Promise的resolve的结果值传递为P的resolve结果值。
- 如果then()中的函数返回了一个不同的值,则这个值会变成P的resolve值。
- 如果then()中的函数抛出了一个意外,则P会因为这个意外而被rejected。
2. Executing asynchronous functions in parallel(并行执行异步函数)
如果你通过then()链式调用Promise,它们就会按顺序执行,一个时间只执行一个Promise
如果你不这样采用链式调用,而是立即调用它们,则它们会并行执行。
而Promise.all()使得你可以一次性获得所有结果。其输入是一个由一系列Promises组成的数组,其输出是一个单个的Promise,其resolve的结果值是一个由一系列结果组成的数组。
Promise.all([
asyncFunc1(),
asyncFunc2(),
])
.then(([result1,result2]) => {
})
.catch(err => {
// Receives first rejection among the Promises
});
二、Promise对象详述
Promise对象用于表示一个异步操作的最终状态(完成或失败),以及其返回的值。
Eg:使用Promise构造函数构造一个promise对象实例:
var promise1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1000, 'foo');//即1s后执行resolve(1)
});
console.log(promise1);//Promise {<resolved>: "foo"}
Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是返回一个能代表未来出现的结果的promise对象。
一个 Promise有以下几种状态:
- pending: 初始状态,既不是成功,也不是失败状态。
- fulfilled/resolved: 意味着操作成功完成。
- rejected: 意味着操作失败。
注意: 如果一个promise对象处在fulfilled或rejected状态而不是pending状态,那么它也可以被称为settled状态。你可能也会听到一个术语resolved ,它表示promise对象处于fulfilled状态。
语法
new Promise(function(resolve, reject){})
param:
- executor: TYPE function 带有resolve和reject两个参数的函数.Promise构造函数执行时立即调用executor 函数, resolve 和 reject 两个函数作为参数传递给executor(executor 函数在Promise构造函数返回新建对象前被调用)。executor 内部通常会执行一些异步操作,一旦完成,可以调用resolve函数来将promise状态改成fulfilled,或者在发生错误时将它的状态改为rejected。
三、Promise类的方法
1. Promise.all(iterable)
返回一个新的Promise实例,此实例在 iterable 参数内所有的 promise 都“完成(resolved)”或参数中不包含 promise 时回调完成(resolve);如果参数中promise有一个失败(rejected),此实例回调失败(reject),失败原因的是第一个失败的promise 的结果。
此方法在集合多个 promise 的返回结果时很有用。
语法
Promise.all(iterable)
param:
- iterable: 一个可迭代对象,如Array或String。
- 如果iterable是一个空的可迭代对象,则返回一个已完成(already resolved)状态的promise;
- 如果iterable中不包含任何promise,则返回一个异步完成(asynchronously resolved)状态的promise;
- 其他情况下返回一个处理中(pending)状态的promise。这个返回的 promise 之后会在所有的 promise 都完成或有一个 promise 失败时异步地变为完成(resolved)或失败(rejected)。
示例1:Promise.all基本用法
var p1 = Promise.resolve(3);
var p2 = 1337;
var p3 = new Promise((resolve,reject) => {
setTimeout(resolve, 1000, 'foo');
});
Promise.all([p1,p2,p3]).then(values => {
console.log(values);//1s后得到:[3, 1337, "foo"]
});
示例2:Promise.all的同步和异步情况
注意: Promise.all当且仅当传入的可迭代对象为空时为同步,其他都是异步的
var p = Promise.all([]); // will be immediately resolved
var p2 = Promise.all([1337, "hi"]); // non-promise values will be ignored, but the evaluation will be done asynchronously
console.log(p);//Promise {<resolved>: Array(0)}
console.log(p2);//Promise {<pending>}
setTimeout(function(){
console.log(p1);//Promise {<resolved>: Array(0)}
console.log(p2);//Promise {<resolved>: Array(2)}
});
示例3:Promise.all之后的链式处理
注意:如果Promise.all传入了若干个promise,如果其中有一个promise立即调用失败函数,其他promise都是在一定时间后调用成功函数,那么Promise.all将立即变为失败。
var p1 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, 'one');
});
var p2 = new Promise((resolve, reject) => {
setTimeout(resolve, 2000, 'two');
});
var p3 = new Promise((resolve, reject) => {
reject('three reject')
});
//使用then()
Promise.all([p1,p2,p3]).then(resultArr => {
console.log(resultArr);
}, err => {
console.log(err);
});
/*控制台输出:
three reject
*/
//或者使用.then().catch()
Promise.all([p1, p2, p3]).then(resultArr => {
console.log(resultArr);
}).catch(err=> {
console.log(err);
})
2. Promise.race(iterable)
返回一个promise,一旦iterable中的某个promise变为resolved或rejected,返回的promise就变为resolved或rejected。
语法
Promise.race(iterable);
param:
- iterable:可迭代对象,类似Array,同1.Promise.all(iterable)的参数iterable
return:
一个promise对象实例,只要给定的iterable中有一个promise变为resolved或rejected,那么就采用第一个状态变为resolved或rejected的这个promise的值,从而异步地变为resolved或rejected。
示例
var p1 = new Promise(function(resolve, reject) {
setTimeout(resolve, 5000, "one");
});
var p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 1000, "two");
});
Promise.race([p1, p2]).then(result => {
console.log(result); // "two"
// 两个都resolved,但 p2 更快,故得到的resolved的promise采用p2 resolve的值
});
3. Promise.resolve(result)
返回一个给定resolve值的resolved状态的promise对象实例。
语法
Promise.resolve(value);
Promise.resolve(promise);
Promise.resolve(thenable);
param:
- 将被Promise对象resolve的值。可以是一个简单值,也可以是一个Promise对象实例,也可以是一个thenable
return:
- 如果参数是一个简单值,则返回一个resolved状态的带着resolved的值的Promise对象;
- 如果参数是一个promise对象,则直接返回这个Promise对象。
- 如果参数是一个thenable对象,则会跟随这个thenable对象,采用它最终状态的Promise
示例1:resolve简单值
Promise.resolve('success').then(result => {
console.log(result);//success
}, (err)=>{
console.log(err); //then的第二个参数这个函数不会被调用
});
示例2:resolve另一个promise对象
var promise1 = Promise.resolve('1');
var promise2 = Promise.resolve(promise1);
promise2.then(result => {
console.log(result);
});
console.log('promise1===promise2:', promise1===promise2);
/* 控制台输出(按顺序)
promise1===promise2: true
1
*/
示例3:resolve thenable对象
var thenableObj = {
then: (resolve,reject) => {
resolve('success');
}
}
console.log(Object.prototype.toString.call(thenableObj));//[object Object]
var promise1 = Promise.resolve(thenableObj);
console.log(promise1 instanceof Promise);//true
promise1.then((result) => {
console.log(result);//'success'
}, (err) => {
console.log(err);//不会调用
});
4. Promise.reject(err)
返回一个带有reject原因err的rejected状态的promise对象。
语法
Promise.reject(err)
param:
- err: 表示rejected的原因。可以为String或Err
return:
一个给定了reject原因的rejected状态的promise。
示例
Promise.reject(new Error("failed")).then(result => {
console.log(result);//then中的第一个函数未被调用
}, err => {
console.log(err);//Error:failed
});
四、Promise实例方法(原型方法)
1. Promise.prototype.then(onResolved, onRejected)
返回一个promise。最多需要两个参数:成功和失败情况的回调函数。
语法
promise.then(onResolved, onReject);
promise.then(result => {
//onResolved
}, err => {
//onRejected
});
Params:
- onResolved: 当promise变成resolved状态时,该参数作为回调函数被调用。该函数有一个参数,即resolve的结果。如果传入的onResolved参数不是函数类型,则会在内部被替换为(result)=>result,此result为then之前的promise resolve的值。
- onRejected: 当promise变成rejected状态时,该参数作为回调函数被调用。该函数有一个参数,即reject的错误原因。
Return:
then方法返回一个Promise,而它的行为与then中的回调函数的返回值有关:
- 如果then中的回调函数返回一个值,那么then返回的Promise将会成为resolved状态,并且将返回的值作为resolved回调函数的参数值。
- 如果then中的回调函数抛出一个错误,那么then返回的Promise将会成为rejected状态,并且将抛出的错误作为rejected回调函数的参数值。
- 如果then中的回调函数返回一个已经是resolved状态的Promise,那么then返回的Promise也会成为resolved状态,并且将那个Promise的resolved状态的回调函数的参数值作为该被返回的Promise的resolved状态回调函数的参数值。
- 如果then中的回调函数返回一个已经是rejected状态的Promise,那么then返回的Promise也会成为rejected状态,并且将那个Promise的rejected状态的回调函数的参数值作为该被返回的Promise的rejected状态回调函数的参数值。
- 如果then中的回调函数返回一个pending状态的Promise,那么then返回Promise的状态也是pending的,并且它的终态与那个Promise的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的。
示例1:传入then的参数不是函数
(new Promise((resolve, reject) => {
resolve('1')
})).then('2')
.then(result => {
console.log(result);//1
})
示例2:链式调用
Promise.resolve('1')
.then(result => {
return new Promise((resolve, reject)=>{
setTimeout(() => {
result += '2';
resolve(result);
}, 1000);
});
}).then(result => {
setTimeout(() => {
result += '3';
console.log(result);//123
//此处没有将新拼接的result resolve
}, 1000);
}).then(result => {
console.log(result);//undefined
});
示例3:链式调用中抛出错误
Promise.resolve()
.then(() => {
throw 'Oh no!';
})
.then(() => {
console.log('Not called');//没有被调用
}, err=>{
console.error('onRejected handler called:', err);//输出错误:onRejected handler called: Oh no!
});
示例4:链式调用中途得到rejected状态的promise
Promise.reject()
.then(
() => 1,//不执行
() => 2//执行
).then(result => {
console.log(result)//2
});
2. Promise.prototype.catch(onRejected)
返回一个promise,并且处理rejected状态。它的行为与调用Promise.prototype.then(undefined, onRejected) 相同。 (事实上, 调用catch(onRejected) 内部调用了then(undefined, onRejected)).
语法
promise.catch(onRejected);
promise.catch(err => {
})
Param:
- onRejected:当promise变为rejected状态时调用的处理函数。该函数拥有一个参数err,为获取的rejected的原因。
注意: 如果 onRejected处理函数抛出一个错误或返回一个本身就是rejected状态的 Promise ,那么通过该catch()返回的Promise会变为rejected状态;否则,它将回是resolved状态。
Return
一个promise
示例
var p1 = new Promise(function(resolve, reject) {
resolve('Success');
});
p1.then(function(value) {
console.log(value); // "Success"
throw 'oh, no!';
}).catch(function(e) {
console.log(e); // "oh, no!"
}).then(function(){
console.log('The promise returned by catch() is resolved'); //'The promise returned by catch() is resolved'
}, function () {
console.log('The promise returned by catch() is rejected');//没有执行
});
3. Promise.prototype.finally(onFinally)
返回一个promise。在执行then()和catch()后,都会执行finally(onFinally)中的onFinnally回调函数。它的意义是避免同样的语句需要在then()和catch()中各写一次的情况。
语法
promise.finally(onFinally);
promise.finally(() => {
})
Param:
- onFinnaly: Promise 状态改变后执行的回调函数。该函数无参数。
Return:
- 一个promise对象
注意:
- 由于无法知道promise的最终状态,所以finally的回调函数中不接收任何参数,它仅用于无论最终结果如何都要执行的情况。
- 与Promise.resolve(2).then(() => {}, () => {}) (resolved的结果为undefined)不同,Promise.resolve(2).finally(() => {}) resolved的结果为 2。
- 同样,Promise.reject(3).then(() => {}, () => {}) (resolved 的结果为undefined), Promise.reject(3).finally(() => {}) rejected 的结果为 3。
参考资料
http://exploringjs.com/es6/ch_promises.html
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise/reject
理解Promise的更多相关文章
- 大白话讲解Promise(二)理解Promise规范
上一篇我们讲解了ES6中Promise的用法,但是知道了用法还远远不够,作为一名专业的前端工程师,还必须通晓原理.所以,为了补全我们关于Promise的知识树,有必要理解Promise/A+规范,理解 ...
- 彻底理解Promise对象——用es5语法实现一个自己的Promise(上篇)
本文同步自我的个人博客: http://mly-zju.github.io/ 众所周知javascript语言的一大特色就是异步,这既是它的优点,同时在某些情况下也带来了一些的问题.最大的问题之一,就 ...
- 理解Promise的三种姿势
译者按: 对于Promise,也许你会用了,却并不理解:也许你理解了,却只可意会不可言传.这篇博客将从3个简单的视角理解Promise,应该对你有所帮助. 原文: Three ways of unde ...
- 理解Promise的3种姿势
译者按: 对于Promise,也许你会用了,却并不理解:也许你理解了,却只可意会不可言传.这篇博客将从3个简单的视角理解Promise,应该对你有所帮助. 原文: Three ways of unde ...
- 分步理解 Promise 的实现
一个 Promise 的运用: var firstPromise = new Promise(function(resolve,reject){ setTimeout(function(){ var ...
- 理解promise 02
1:promise是什么? 就是(链式)包装的回调函数. 2:语法 new Promise( function(resolve, reject) {...} /* executor */ ); exe ...
- 160701、理解 Promise 的工作原理
Javascript 采用回调函数(callback)来处理异步编程.从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doo ...
- 160623、理解 Promise 的工作原理
Javascript 采用回调函数(callback)来处理异步编程.从同步编程到异步回调编程有一个适应的过程,但是如果出现多层回调嵌套,也就是我们常说的厄运的回调金字塔(Pyramid of Doo ...
- 理解Promise简单实现的背后原理
在写javascript时我们往往离不开异步操作,过去我们往往通过回调函数多层嵌套来解决后一个异步操作依赖前一个异步操作,然后为了解决回调地域的痛点,出现了一些解决方案比如事件订阅/发布的.事件监听的 ...
- 理解promise 01
原文地址: http://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html 用Javascript的小伙伴们,是时候承认了,关于 ...
随机推荐
- 9.接口BeanPostProcessor
package org.springframework.beans.factory.config; import org.springframework.beans.BeansException; p ...
- python爬虫之request and BeautifulSoup
1.爬虫的本质是什么? 模仿浏览器的行为,爬取网页信息. 2.requests 1.get请求 无参数实例 import requests ret = requests.get('https://gi ...
- Docker dubbo 服务注册
vim run.sh #!/bin/baship=`ifconfig eth0 |grep "inet"|awk '{print $2}'`hn=dubbo-service-pro ...
- 第12条:不要在for和while循环后面写else块
核心知识点: (1)一般的if/else是前面不执行,后面才执行,循环下面的else是前面执行完后面才会执行,如果是break打断也不会执行.循环为空或False也不执行. (2)try/expect ...
- pinpoint改造支持查询
原架构 改造后架构
- [原创]java WEB学习笔记10:GenericServlet
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...
- Python导出数据生成excel报表
#_*_coding:utf-8_*_ import MySQLdb import xlwt from datetime import datetime def get_data(sql): # 创建 ...
- jquery 初篇
一.什么是jQuery对象? jQuery 对象就是通过jQuery包装DOM对象后产生的对象. jQuery 对象是 jQuery 独有的. 如果一个对象是 jQuery 对象, 那么它就可以使用 ...
- 为UniDBEdit添加拖拽属性
不知是作者Fashard的疏忽还是有意,UniDBEdit的拖拽属性居然没有发布出来(其他组件都已发布).加上其实也很简单. 打开source目录下的uniDBEdit.pas单元,在TUniDBEd ...
- C++难点的一些总结
一. C++成员函数的重载 C++中的成员函数有四种,分别是普通成员函数,virtual虚函数,const成员函数. (1) void func(int a); (2) virtual void fu ...