ES6 -- 异步编程神器:Promise对象
来源:互联网 发布:快手红人淘宝店铺大全 编辑:程序博客网 时间:2024/05/21 04:17
Promise是一种异步编程的解决方案,比起传统的回调函数方式,Promise要更合理和强大。
基本调用方式
下面直接给出代码,通过代码对Promise对象进行讲解和分析:
构造一个Promise实例的模版代码:
var promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操作成功 */){ resolve(value); } else { reject(error); }});promise.then(function(value) { // success}, function(error) { // failure});
首先,Promise在ES6中是一个构造函数,用来生成Promise实例。所以,当我们需要Promise对象的时候,直接用new Promise(…)这样的方式即可。
我们调用new Promise方法的时候,它接受一个函数作为参数,而这个函数的两个参数分别是resolve, reject(我们现在并不用关心这个函数以及它的参数是从何而来的,我们首先只要按照这样的格式书写代码并会用就可以了),resolve和reject这两个参数其实也都是系统提供的函数,我们可以在这个函数中(也就是如上代码中// … some code的后面)的适当时机(比如:异步调用成功/失败后)可以直接调用它们。
调用后,Promise对象就会自动的触发then方法,如果我们调用了resolve方法,表示异步调用成功,那么就会执行作为then方法第一个参数的函数;如果我们调用了reject方法,表示异步调用失败,那么就会执行作为then方法第二个参数的函数。
补充一点:Promise对象有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和Rejected(已失败)。调用resolve方法可以使Promise对象的状态从“未完成”变为“成功”(即从Pending变为Resolved),而reject则将Promise对象的状态从“未完成”变为“失败”(即从Pending变为Rejected)。这两个函数都可以传递参数value或error,将可以将异步操作的结果传递出去,我们可以在then方法的参数(其实也是一个函数)中取到这个value或error。
另外,Promise新建后就会立即执行。
再看一个具体的例子,图片的异步获取:
function loadImageAsync(url) { return new Promise(function(resolve, reject) { var image = new Image(); image.onload = function() { resolve(image); }; image.onerror = function() { reject(new Error('Could not load image at ' + url)); }; image.src = url; });}
这个栗子只写了第一段代码模版的第一部分,在这段代码中,我们就能清楚的看到何时以及如何调用resolve方法和reject方法:在图片加载成功的回调函数中调用了resolve,在图片加载失败的回调函数中调用了reject。
resolve参数的另一种可能
在前文中我们已经知道了:如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。
reject函数的参数通常是Error对象的实例,表示抛出的错误,这样,我们在回调函数中就可以接受并处理这个错误;resolve函数的参数除了正常的值以外,还可能是另一个Promise实例,表示异步操作的结果有可能是另一个异步操作。
例如:
var p1 = new Promise(function (resolve, reject) { // ...});var p2 = new Promise(function (resolve, reject) { // ... resolve(p1);})
此时,p1的状态就会决定p2的状态——如果p1的状态是Pending,那么p2的回调函数就会等待p1的状态改变;如果p1的状态已经是Resolved或者Rejected,那么p2的回调函数将会立刻执行。
栗子:
var p1 = new Promise(function (resolve, reject) { setTimeout(() => reject(new Error('fail')), 3000)})var p2 = new Promise(function (resolve, reject) { setTimeout(() => resolve(p1), 1000)})p2 .then(result => console.log(result)) .catch(error => console.log(error))// Error: fail
上面代码中,Promise实例p1在3秒之后变为rejected。而p2的状态在1秒之后改变,但是resolve方法返回的是p1。由于p2返回的是另一个 Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。所以,后面的then语句都变成针对后者(p1)。又过了2秒,p1变为rejected,才能导致触发catch方法指定的回调函数。
关于then方法的链式调用
then方法定义在Promise.prototype上,也就是说,是Promise实例的方法。因此,如果then方法中返回一个新的Promise实例,那么,then方法就可以被链式的调用,事实上,也正是如此;但是需要注意,then方法中返回的Promise已经不是调用then的那个Promise对象了,它是一个全新的promise对象。
例如像这样:
注:then方法中,第二个参数(对错误的处理函数)可以省略。
getJSON("/posts.json").then(function(json) { return json.message;}).then(function(message) { // ...});
由于getJSON返回的是一个Promise对象,那么它后面的then函数就会等待这个Promise对象的状态发生变化后被执行。而在这个then函数中,返回的json.message并不是一个异步操作,那么,它下面的一个then(第二个then)就会直接被调用。而如果,在这个then函数中返回的是一个promise对象,那么第二个then函数就会等到这个promise完成后(状态变为resolve或者reject)执行。
在下面这个栗子中,几个then函数会接连被调用,依次显示hello, world, !。
function printHello (ready) { return new Promise(function (resolve, reject) { if (ready) { resolve("Hello"); } else { reject("Good bye!"); } });}function printWorld () { alert("World");}function printExclamation () { alert("!");}printHello(true) .then(function(message){ alert(message); }) .then(printWorld) .then(printExclamation);
catch方法
Promise.prototype.catch方法是.then(null, rejection)的别名,(也就是then方法调用时省略第一个参数),它用于指定发生错误时的回调函数。
p1.then(function(posts) { // ...}).catch(function(error) { // 处理 getJSON 和 前一个回调函数运行时发生的错误 console.log('发生错误!', error);});
在上面这个栗子中,假设p1是一个已经定义过的promise对象,当p1中异步操作执行完毕,如果p1状态变为resolve,就会触发第一个then方法;如果p1状态变为reject,则会触发后面的catch方法(因为promise的错误具有冒泡的性质,会一直向后传递,直到被捕获)。同时,如果p1的then方法出现了错误,也会被catch函数捕获。
同时,由于catch函数实际上是then(null,rejection)的别名,所以在catch后,还可以继续链式调用then和catch函数。
由于Promise的错误具有冒泡的性质,于是建议大家总是使用catch,而不要在then方法中定义reject时的回调函数:
// 不推荐这种写法,这样在then的第一个函数参数中出现的错误无法被捕获promise1 .then(function(data) { // success }, function(err) { // error });// 推荐的方法,这种情况下,错误一定能被捕获promise2 .then(function(data) { // success }) .catch(function(err) { // error });
另外,在非chrome浏览器中,promise对象中出现的错误不会被传递到外层代码。
- ES6 -- 异步编程神器:Promise对象
- ES6 -- 异步编程神器2:Generator
- 【ES6学习】— (2)异步编程Generator函数和Promise对象简介
- 《深入理解ES6》阅读笔记 --- Promise与异步编程
- ES6 异步编程(一)——Promise
- Javascript的异步编程(上)及es6的promise
- es6 promise对象
- ES6 Promise 对象
- ES6 Promise对象
- ES6 Promise对象学习心得
- ES6中的promise对象
- ES6(六) promise对象
- 浅谈ES6 Promise对象
- ES6 Promise 对象理解
- ES6 -- Promise对象
- ES6之Promise对象
- JS异步编程(promise、deferred对象)
- js异步之promise(ES6)
- 转:我希望进入大学时就能知道的一些事儿
- ubuntu下怎么显示右上角的小键盘
- linux命令之wget
- 远程管理 KVM 虚机
- 插入排序
- ES6 -- 异步编程神器:Promise对象
- 箭头函数 generator
- 新完整包
- 【思路】嵌套List针对某index进行排序
- Java处理json 取json值
- Android Studio中新建的工程中使用了Module,从app中去调用Module中的东西,需要如何操作。
- MongoDB3.4 shell CRUD操作
- waveInStop死锁
- 2017.05.04回顾 线性可分的一些问题引出