Promise定义

Promise是CommonJs的规范之一,包含resolve,reject,done,fail,then等方法,能够帮助我们控制代码的流程,避免函数的多层嵌套。异步在web开发中越来越重要,对于开发人员来说,J非线性执行的编程会让开发者觉得难以掌控,而Promise可以让我们更好地掌控代码的执行流程,jQuery等流行的js库都已经实现了这个对象,现在ES6已经原生实现了Promise。

场景说明:

有时候会遇到这样的情况,需要发两个异步请求,而第二个请求需要用到第一个返回结果的数据:

ajax({
url: url1,
success: function(data) {
ajax({
url: url2,
data: data,
success: function() {
}
});
}
});

稍微整理一下,把后一个调用封装成一个函数,就是酱紫滴:

    function A() {
ajax({
url: url1,
success: function(data) {
B(data);
}
});
}
function B(data) {
ajax({
url: url2,
success: function(data) {
......
}
});
}

如果异步请求C又需要用到B的结果,又需要一层。如果需要很多层,代码可读性会降低,最后不忍直视了就。所以就有了Promise。有了Promise,代码就是酱紫了:

new Promise(A).done(B);

很清爽很DRY有木有?

ES6已经实现了Promise,不过也可以自己写一个Promise对象:

用两个数组(doneList和failList)来存储成功时的回调函数队列和失败时的回调函数队列。

此对象的方法和属性:

1.state: 当前执行状态,有pending、resolved、rejected3种取值

2.done: 向doneList中添加一个成功回调函数

3.then: 分别向doneList和failList中添加回调函数

4.always: 添加一个无论成功还是失败都会调用的回调函数

5.resolve: 将状态更改为resolved,并触发绑定的所有成功的回调函数

6.reject: 将状态更改为rejected,并触发绑定的所有失败的回调函数

7.when: 参数是多个异步或者延迟函数,返回值是一个Promise兑现,当所有函数都执行成功的时候执行该对象的resolve方法,反之执行该对象的reject方法

具体实现:

var Promise = function() {
this.doneList = [];
this.failList = [];
this.state = 'pending';
}; Promise.prototype = {
constructor: 'Promise',
resolve: function() {
this.state = 'resolved';
var list = this.doneList;
for(var i = 0, len = list.length; i < len; i++) {
list[0].call(this);
list.shift();
}
},
reject: function() {
this.state = 'rejected';
var list = this.failList;
for(var i = 0, len = list.length; i < len; i++){
list[0].call(this);
list.shift();
}
},
done: function(func) {
if(typeof func === 'function') {
this.doneList.push(func);
}
return this;
},
fail: function(func) {
if(typeof func === 'function') {
this.failList.push(func);
}
return this;
},
then: function(doneFn, failFn) {
this.done(doneFn).fail(failFn);
return this;
},
always: function(fn) {
this.done(fn).fail(fn);
return this;
}
};

这个不支持链式调用,可以再来个支持链式调用的:

var MPromise = function(func){
this.doneList = [];
this.state = 'pending';
func(this.resolve.bind(this));
this.self = this;
}
MPromise.prototype = {
resolve: function(){
var args = arguments[0]; while(true){
args = [args];
this.lastargs = args; if( this.doneList.length == 0 ){
this.state = 'done';
break;
} args = this.doneList.shift().apply(this, args); if( args instanceof MPromise ){
this.self = args;
args.doneList = args.doneList.concat(this.doneList.slice(0));
this.state = 'done';
this.doneList.length = 0;
break;
}
}
},
then: function(callback){
this.doneList.push(callback);
if( this.state == 'done' ){
this.state = 'pending';
this.resolve.apply(this, this.lastargs);
}
return this.self;
}
}

ES6-Promise

ES6提供了原生Promise对象:从语法上说,Promise是一个对象,从中可以获取异步操作的消息。

基本用法:

ES6中的Promise对象是一个构造函数,用来生成Promise实例。

var promise = new Promise(function(resolve, reject) {
// ... some code if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});

Promise对象接收一个函数作为参数,这个函数的两个参数分别是resolve和reject,这两个函数由Javascript引擎提供,不用自己部署。

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从Pending变为Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从Pending变为Rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。

promise.then(function(value) {
// success
}, function(error) {
// failure
});

then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为Resolved时调用,第二个回调函数是Promise对象的状态变为Reject时调用。其中,第二个函数是可选的,不一定要提供。这两个函数都接受Promise对象传出的值作为参数。

一个Promise的简单例子:

function timeout(ms) {
return new Promise((resolve, reject) => {
setTimeout(resolve, ms, 'done');
});
} timeout(100).then((value) => {
console.log(value);
});

timeout返回了一个Promise实例,延迟一段时间再执行,超过指定时间之后,Promise实例的状态会变成Resolved,会触发then方法绑定的回调函数。

Promise新建后会立即执行:

let promise = new Promise(function(resolve, reject) {
console.log('Promise');
resolve();
}); promise.then(function() {
console.log('Resolved.');
}); console.log('Hi!'); // Promise
// Hi!
// Resolved

如上,Promise新建之后立即执行,所以首先输出Promise,然后then方法指定的回调函数,是在当前所有脚本执行之后才执行,所以Resolved最后输出。

一个异步加载图片的例子:

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;
});
}

这里使用Promise封装了一个图片懒加载,加载成功则调用resolve方法,加载失败会调用rejected方法。

下面是一个用Promise实现Ajax调用的栗子:

var getJSON = function(url) {
var promise = new Promise(function(resolve, reject){
var client = new XMLHttpRequest();
client.open("GET", url);
client.onreadystatechange = handler;
client.responseType = "json";
client.setRequestHeader("Accept", "application/json");
client.send(); function handler() {
if (this.readyState !== 4) {
return;
}
if (this.status === 200) {
resolve(this.response);
} else {
reject(new Error(this.statusText));
}
};
}); return promise;
}; getJSON("/posts.json").then(function(json) {
console.log('Contents: ' + json);
}, function(error) {
console.error('Error', error);
});

上面getJSON是对XMLHttpRequest的封装,用来发一个对JSON数据的Http请求,并且返回一个Promise对象。在getJSON内部,resolve和reject函数调用时,都带有参数。

如果调用resolve函数和reject函数时带有参数,那么参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个Promise实例,表示异步操作的结果有可能是一个值,也有可能是另一个异步操作,比如像下面这样。

var p1 = new Promise(function (resolve, reject) {
// ...
}); var p2 = new Promise(function (resolve, reject) {
// ...
resolve(p1);
})

上面代码里面的p1和p2都是Promise的实例,但是p2的resolve方法将p1作为参数,即一个异步操作结果是另外一个异步操作。

这里p1的状态就会传到p2,也就是,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))
p2.catch(error => console.log(error))
// Error: fail

上面代码中,p1是一个Promise,3秒之后变为rejected。p2的状态由p1决定,1秒之后,p2调用resolve方法,但是此时p1的状态还没有改变,因此p2的状态也不会变。又过了2秒,p1变为rejected,p2也跟着变为rejected。

参考:http://es6.ruanyifeng.com/#docs/promise

Javascript中的Promise的更多相关文章

  1. javascript中的promise和deferred:实践(二)

    javascript中的promise和deferred:实践(二) 介绍: 在第一节呢,我花了大量的时间来介绍promises和deferreds的理论.现在呢,我们来看看jquery中的promi ...

  2. JavaScript中的Promise【期约】[未完成]

    JavaScript中的Promise[期约] 期约主要有两大用途 首先是抽象地表示一个异步操作.期约的状态代表期约是否完成. 比如,假设期约要向服务器发送一个 HTTP 请求.请求返回 200~29 ...

  3. 快速入门上手JavaScript中的Promise

    当我还是一个小白的时候,我翻了很多关于Promise介绍的文档,我一直没能理解所谓解决异步操作的痛点是什么意思 直到我翻了谷歌第一页的所有中文文档我才有所顿悟,其实从他的英文字面意思理解最为简单粗暴 ...

  4. 通过一道笔试题浅谈javascript中的promise对象

    因为前几天做了一个promise对象捕获错误的面试题目,所以这几天又重温了一下promise对象.现在借这道题来分享下一些很基础的知识点. 下面是一个面试题目,三个promise对象捕获错误的例子,返 ...

  5. 掌握JavaScript中的Promise,实现异步编程

    事件循环 基本介绍 JavaScript是一门单线程的编程语言,所以没有真正意义上的并行特性. 为了协调事件处理.页面交互.脚本调用.UI渲染.网络请求等行为对主线程造成的影响,事件循环(event ...

  6. 彻底理解Javascript 中的 Promise(-------------------------------***---------------------------------)

    ES6原生提供了 Promise 对象. 到底是何方妖怪呢?打出来看看: 所谓 Promise,就是一个对象,用来传递异步操作的消息.它代表了某个未来才会知道结果的事件(通常是一个异步操作),并且这个 ...

  7. javascript中的Promise使用

    参考自: http://m.jb51.net/article/102642.htm 1.基本用法: (1).首先我们new一个Promise,将Promise实例化 (2).然后在实例化的promis ...

  8. 全面理解Javascript中Promise

    全面理解Javascript中Promise 最近在学习Promise的时候,在网上收集了一些资料,发现很多的知识点不够系统,所以小编特意为大家整理了一些自认为 比较好的文章,供大家更好地学习js中非 ...

  9. 深入理解 JavaScript 异步系列(3)—— ES6 中的 Promise

    第一部分,Promise 加入 ES6 标准 原文地址 http://www.cnblogs.com/wangfupeng1988/p/6515855.html 未经作者允许不得转载! 从 jquer ...

随机推荐

  1. 三级联动(在YII框架中)

    //三级联动 //数据库代码过多就不上传了 //视图 <div class="area">    <table class="table"&g ...

  2. System.DateUtils 2. IsInLeapYear 判断是否是闰年

    编译版本:Delphi XE7 function IsInLeapYear(const AValue: TDateTime): Boolean; implementation // 判断是否是闰年 f ...

  3. php统计网站访问次数的一个简单方法

    这里主要用到了session保存当前访问者,并将访问次数写入本地文件. <? @session_start(); $counter = intval(file_get_contents(&quo ...

  4. C# 下载搜狗词库

    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); string[] userAgent = new string[]{& ...

  5. linux学习笔记--vi与vim编辑器

    vi编辑器全名为Visual Interface,即为可视化接口,类似于Windows中的记事本 vim相当于是vi的一个升级版本,包含vi的一切操作命令,vim相对于vi做了哪些提升: 1.vim支 ...

  6. git常见命令

    总结自己的Git常用命令 使用git也有一段时间了,把自己常用的命令用自己的描述记录起来,方便自己备忘也方便其他人参考. 目录: 最基本的命令: git clone 拷贝并跟踪远程的master分支. ...

  7. UIAlertView和UIActivityIndicatorView的使用

    UIAlertView用来显示一个对话框,可以设置对话框的标题.文案.按钮的个数和文案,也可以通过实现delegate来监听按钮的的点击操作. 使用UIAlertView时需要注意: self.ale ...

  8. C++中vector的remove用法

      我将从remove的复习开始这个条款,因为remove是STL中最糊涂的算法.误解remove很容易,驱散所有关于remove行为的疑虑——为什么它这么做,它是怎么做的——是很重要的. 这是rem ...

  9. 01.Bootstrap入门

    Bootstrap介绍: Bootstrap,来自 Twitter,是目前很受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.JAVASCRIPT 的,它简洁灵活,使得 Web 开发更加 ...

  10. web前端响应式

    一.响应式概述: 不仅仅是通过屏幕尺寸来动态改变页面容器的宽度等,完整的响应式网站的实现需要考虑到这些问题:响应式布局.响应式html和css.响应式媒体.响应式javascript. 二.移动端布局 ...