Promise API 简介

译者注: 到处是回调函数,代码非常臃肿难看, Promise 主要用来解决这种编程方式, 将某些代码封装于内部。

Promise 直译为“承诺”,但一般直接称为 Promise;

代码的可读性非常重要,因为开发人员支出一般比计算机硬件的支出要大很多倍。

虽然同步代码更容易跟踪和调试, 但异步方式却具有更好的性能与灵活性.

怎样在同一时刻发起多个请求, 然后分别处理响应结果? Promise 现已成为 JavaScript 中非常重要的一个组成部分, 很多新的API都以 promise 的方式来实现。下面简要介绍 promise, 以及相应的 API 和使用示例!

Promises 周边

XMLHttpRequest 是异步API, 但不算 Promise 方式。当前使用 Promise 的原生 api 包括:

Promise 会越来越流行,所以前端开发需要快速掌握它们。当然, Node.js 是另一个使用 Promise 的平台(显然, Promise 在Node中是一个核心特性)。

测试 promises 可能比你想象的还要容易, 因为 setTimeout 可以用来当作异步“任务”!

Promise 基本用法

直接使用 new Promise() 构造函数的方式, 应该只用来处理遗留的异步任务编程, 例如 setTimeout 或者 XMLHttpRequest。 通过 new 关键字创建一个新的 Promise 对象, 该对象有 resolve(搞定!) 和 reject(拒绝!) 两个回调函数:

var p = new Promise(function(resolve, reject) {
// ... ...
// 此处,可以执行某些异步任务,然后...
// 在回调中,或者任何地方执行 resolve/reject if(/* good condition */) {
resolve('传入成果结果信息,如 data');
}
else {
reject('失败:原因...!');
}
}); p.then(function(data) {
/* do something with the result */
}).catch(function(err) {
/* error :( */
});

一般是由开发人员根据异步任务执行的结果,来手动调用 resolve 或者 reject. 一个典型的例子是将 XMLHttpRequest 转换为基于Promise的任务:

// 本段示例代码来源于 Jake Archibald's Promises and Back:
// http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promisifying-xmlhttprequest function get(url) {
// 返回一个 promise 对象.
return new Promise(function(resolve, reject) {
// 执行常规的 XHR 请求
var req = new XMLHttpRequest();
req.open('GET', url); req.onload = function() {
// This is called even on 404 etc
// so check the status
if (req.status == 200) {
// Resolve the promise with the response text
resolve(req.response);
}
else {
// Otherwise reject with the status text
// which will hopefully be a meaningful error
reject(Error(req.statusText));
}
}; // Handle network errors
req.onerror = function() {
reject(Error("网络出错"));
}; // Make the request
req.send();
});
}; // 使用!
get('story.json').then(function(response) {
console.log("Success!", response);
}, function(error) {
console.error("Failed!", error);
});

有时候在 promise 方法体中不需要执行异步任务 —— 当然,在有可能会执行异步任务的情况下, 返回 promise 将是最好的方式, 这样只需要给定结果处理函数就行。在这种情况下, 不需要使用 new 关键字, 直接返回 Promise.resolve() 或者 Promise.reject()即可。例如:

var userCache = {};

function getUserDetail(username) {
// In both cases, cached or not, a promise will be returned if (userCache[username]) {
// Return a promise without the "new" keyword
return Promise.resolve(userCache[username]);
} // Use the fetch API to get the information
// fetch returns a promise
return fetch('users/' + username + '.json')
.then(function(result) {
userCache[username] = result;
return result;
})
.catch(function() {
throw new Error('Could not find user: ' + username);
});
};

因为总是会返回 promise, 所以只需要通过 thencatch 方法处理结果即可!

then

每个 promise 实例都有 then 方法, 用来处理执行结果。 第一个 then 方法回调的参数, 就是 resolve() 传入的那个值:

new Promise(function(resolve, reject) {
// 通过 setTimeout 模拟异步任务
setTimeout(function() { resolve(10); }, 3000);
})
.then(function(result) {
console.log(result);
}); // console 输出的结果:
// 10

then 回调由 promise 的 resolved 触发。你也可以使用链式的 then` 回调方法:

new Promise(function(resolve, reject) {
// 通过 setTimeout 模拟异步任务
setTimeout(function() { resolve(10); }, 3000);
})
.then(function(num) { console.log('first then: ', num); return num * 2; })
.then(function(num) { console.log('second then: ', num); return num * 2; })
.then(function(num) { console.log('last then: ', num);}); // console 输出的结果:
// first then: 10
// second then: 20
// last then: 40

每个 then 收到的结果都是之前那个 then 返回的值。

如果 promise 已经 resolved, 但之后才调用 then 方法, 则立即触发回调。如果promise被拒绝之后才调用 then, 则回调函数不会被触发。

catch

当 promise 被拒绝时, catch 回调就会被执行:

new Promise(function(resolve, reject) {
// 通过 setTimeout 模拟异步任务
setTimeout(function() { reject('Done!'); }, 3000);
})
.then(function(e) { console.log('done', e); })
.catch(function(e) { console.log('catch: ', e); }); // console 输出的结果:
// 'catch: Done!'

传入 reject 方法的参数由你自己决定。一般来说是传入一个 Error 对象:

reject(Error('Data could not be found'));

Promise.all

想想JavaScript加载器的情形: 有时候会触发多个异步交互, 但只在所有请求完成之后才会做出响应。—— 这种情况可以使用 Promise.all 来处理。Promise.all 方法接受一个 promise 数组, 在所有 promises 都搞定之后, 触发一个回调:

Promise.all([promise1, promise2]).then(function(results) {
// Both promises resolved
})
.catch(function(error) {
// One or more promises was rejected
});

Promise.all 的最佳示例是通过fetch同时发起多个 AJAX请求时:

var request1 = fetch('/users.json');
var request2 = fetch('/articles.json'); Promise.all([request1, request2]).then(function(results) {
// Both promises done!
});

你也可以组合使用 fetch 和 Battery 之类的 API ,因为他们都返回 promises:

Promise.all([fetch('/users.json'), navigator.getBattery()]).then(function(results) {
// Both promises done!
});

当然, 处理拒绝的情况比较复杂。如果某个 promise 被拒绝, 则 catch 将会被第一个拒绝(rejection)所触发:

var req1 = new Promise(function(resolve, reject) {
// 通过 setTimeout 模拟异步任务
setTimeout(function() { resolve('First!'); }, 4000);
});
var req2 = new Promise(function(resolve, reject) {
// 通过 setTimeout 模拟异步任务
setTimeout(function() { reject('Second!'); }, 3000);
});
Promise.all([req1, req2]).then(function(results) {
console.log('Then: ', one);
}).catch(function(err) {
console.log('Catch: ', err);
}); // From the console:
// Catch: Second!

随着越来越多的 API 支持 promise, Promise.all 将会变得超级有用。

Promise.race

Promise.race 是一个有趣的函数. 与 Promise.all 相反, 只要某个 priomise 被 resolved 或者 rejected, 就会触发 Promise.race:

var req1 = new Promise(function(resolve, reject) {
// 通过 setTimeout 模拟异步任务
setTimeout(function() { resolve('First!'); }, 8000);
});
var req2 = new Promise(function(resolve, reject) {
// 通过 setTimeout 模拟异步任务
setTimeout(function() { resolve('Second!'); }, 3000);
});
Promise.race([req1, req2]).then(function(one) {
console.log('Then: ', one);
}).catch(function(one, two) {
console.log('Catch: ', one);
}); // From the console:
// Then: Second!

一个案例是请求的资源有 主站资源和备用资源(以防某个不可用)。

改变习惯, 使用 Promise

在过去几年中 Promise 一直是个热门话题(如果你是 Dojo Toolkit 用户,那么就是已经有10年了), 已经从一个JavaScript框架变成了语言的一个主要成分. 很快你就会看到大多数新的 JavaScript api 都会基于 Promise 的方式来实现……

... 当然这是一件好事! 开发人员能够避开回调的地狱, 异步交互也可以像其他变量一样传递. Promise 还需要一段时间来普及, 现在是时候去学习他们了!

本文转载自:众成翻译

译者:铁胖子

链接:http://www.zcfy.cc/article/351

原文:https://davidwalsh.name/promises

Promise API 简介的更多相关文章

  1. web API简介(一):API,Ajax和Fetch

    概述 今天逛MDN,无意中看到了web API简介,觉得挺有意思的,就认真读了一下. 下面是我在读的时候对感兴趣的东西的总结,供自己开发时参考,相信对其他人也有用. 什么是API API (Appli ...

  2. Web Api 简介

    ASP.NET Web API 简介  ASP.NET MVC 4 包含了 ASP.NET Web API, 这是一个创建可以连接包括浏览器.移动设备等多种客户端的 Http 服务的新框架, ASP. ...

  3. ZooKeeper系列4:ZooKeeper API简介及编程

    问题导读: 1.ZooKeeper API 共包含几个包? 2.如何使用ZooKeeper API 创建zookeeper应用程序? 1)ZooKeeper API 简介   ZooKeeper AP ...

  4. JavaScript Promise API

    同步编程通常来说易于调试和维护,然而,异步编程通常能获得更好的性能和更大的灵活性.异步的最大特点是无需等待."Promises"渐渐成为JavaScript里最重要的一部分,大量的 ...

  5. WebSocket API简介

    WebSocket是html5新增加的一种通信协议,目前流行的浏览器都支持这个协议,例如Chrome,Safari,Firefox,Opera,IE等等,对该协议支持最早的应该是chrome,从chr ...

  6. 构建简单的 C++ 服务组件,第 1 部分: 服务组件体系结构 C++ API 简介

    构建简单的 C++ 服务组件,第 1 部分: 服务组件体系结构 C++ API 简介 熟悉将用于 Apache Tuscany SCA for C++ 的 API.您将通过本文了解该 API 的主要组 ...

  7. Raphael Js矢量库API简介:

    Raphael Js矢量库API简介:Raphael Javascript 是一个 Javascript的矢量库. 2010年6月15日,著名的JavaScript库ExtJS与触摸屏代码库项目jQT ...

  8. 【译】JavaScript Promise API

    原文地址:JavaScript Promise API 在 JavaScript 中,同步的代码更容易书写和 debug,但是有时候出于性能考虑,我们会写一些异步的代码(代替同步代码).思考这样一个场 ...

  9. 开放数据接口 API 简介与使用场景、调用方法

    此文章对开放数据接口 API 进行了功能介绍.使用场景介绍以及调用方法的说明,供用户在使用数据接口时参考之用. 在给大家分享的一系列软件开发视频课程中,以及在我们的社区微信群聊天中,都积极地鼓励大家开 ...

随机推荐

  1. 团体程序设计天梯赛-练习集-L1-047. 装睡

    L1-047. 装睡 你永远叫不醒一个装睡的人 —— 但是通过分析一个人的呼吸频率和脉搏,你可以发现谁在装睡!医生告诉我们,正常人睡眠时的呼吸频率是每分钟15-20次,脉搏是每分钟50-70次.下面给 ...

  2. 【转载】VMware完全卸载

    出现安装时出现vmwareworkstationxxx.msi failed问题是官方解决方案...真心详细. http://kb.vmware.com/selfservice/microsites/ ...

  3. [IOI2007]矿工配餐

    状态是f[i][a][b][c][d]表示第i个餐车,1号矿洞最近两顿是a,b,2号矿洞最近两顿是c,d. 给的空间是16MB,滚动数组滚动了第一维就行了 (给的变量是char是因为这个不超过256, ...

  4. js中writeln()方法

    writeln( ) 方法与 write( ) 方法几乎一样,差别仅在于是前者将在所提供的任何字符串后添加一个换行符.在 HTML 中,这通常只会在后面产生一个空格:不过如果使用了 <PRE&g ...

  5. WPF通过鼠标滑轮缩放显示图片

    如果你使用WinForm比较难实现通过滚动鼠标滑轮来对图片进行缩放显示,那么,你应该考虑一下使用WPF,既然是下一代Windows客户端开发平台,明显是有一定优势的,不然,MS是吃饱了撑着.   首先 ...

  6. 【Codeforces Round #519 by Botan Investments A】 Elections

    [链接] 我是链接,点我呀:) [题意] [题解] 枚举k 那么另外一个人的得票就是nk-sum(ai) 找到最小的满足nk-sum(ai)>sum(ai)的k就ok了 [代码] #includ ...

  7. emacs 搭建racket开发环境

    emacs 搭建racket开发环境 emacs下搭建开发racket的环境,笔者之前用过下面两种模式:geiser和racket-mode.相对而言,后一种方式要显得简单.本文主要介绍后一种方式环境 ...

  8. jquery非文本框复制

    function selectText(x) { if (document.selection) { var range = document.body.createTextRange();//ie ...

  9. Mac下搭建hexo3.0博客

    Mac下搭建hexo3.0博客(文章同步自个人博客站点以及Github博客https://xingstarx.github.io/) window环境下搭建hexo博客 详细内容能够參考这一篇文章怎样 ...

  10. Mina airQQ聊天开门见山篇(一)

    Mina airQQ聊天开门见山篇(一) 近期项目可能要用到Mina,这个礼拜就在看这个框架,所以想写个小小的聊天的demo来巩固下,打算用几篇博客来记录下相关的知识 client用的是Flex Ai ...