ES6之Promise
Promise 基础
Promise 是为异步操作的结果所准备的占位符。是解决异步编程的一种方法,是规避回调地狱(callbacK hell)的一种解决方案
Promise 的生命周期
- 创建时是一个未决状态,白话文就是还没有决定结果
- 已完成( fulfilled ): Promise 的异步操作已成功结束;
- 已拒绝( rejected ): Promise 的异步操作未成功结束,可能是一个错误,或由其他原
因导致。
Promise的方法
promise有以下方法:
- then()
- catch()
- all()
- race()
then()方法
promise.then()接受两个参数。第一个参数是Promise被完成时要调用的函数,与异步操作关联的任何附加数据都会被传入这个完成函数。第二个参数则是Promise被拒绝时要调用的函数,与完成函数相似,拒绝函数会被传入与拒绝相关联的任何附加数据。
如下:
let promise = readFile("example.txt");
promise.then(function(contents) {
// 完成
console.log(contents);
}, function(err) {
// 拒绝
console.error(err.message);
});
catch()方法
其行为等同于只传递拒绝处理函数给 then() 。例如,以下的 catch() 与then()调用是功能等效的。
promise.catch(function(err) {
// 拒绝
console.error(err.message);
});
// 等同于:
promise.then(null, function(err) {
// 拒绝
console.error(err.message);
});
创建一个未决的Promise()
新的 Promise 使用 Promise 构造器来创建。此构造器接受单个参数:一个被称为执行器(
executor )的函数,包含初始化 Promise 的代码。该执行器会被传递两个名为 resolve()
与 reject() 的函数作为参数。 resolve() 函数在执行器成功结束时被调用,用于示意该
Promise 已经准备好被决议( resolved ),而 reject() 函数则表明执行器的操作已失败。
// Node.js 范例
let fs = require("fs");
function readFile(filename) {
return new Promise(function(resolve, reject) {
// 触发异步操作
fs.readFile(filename, { encoding: "utf8" }, function(err, contents) {
// 检查错误
if (err) {
reject(err);
return;
}
// 读取成功
resolve(contents);
});
});
}
let promise = readFile("example.txt");
// 同时监听完成与拒绝
promise.then(function(contents) {
// 完成
console.log(contents);
}, function(err) {
// 拒绝
console.error(err.message);
});
//等同于
promise.then((contents)=>{
// 完成
console.log(contents);
}).catch((err)=>{
// 拒绝
console.error(err.message);
});
以上是一个基本的Promise模型,then()方法执行fs.readFile()读取文件成功后的回调函数,catch()方法执行读取文件失败后的错误回调
创建已决的 Promise
即创建的时候就决定了结果,Promise.resolve() 方法接受单个参数并会返回一个处于完成态的 Promise 。
let promise = Promise.resolve(42);
promise.then(function(value) {
console.log(value); // 42
});
Promise.reject() 方法来创建一个已拒绝的 Promise 。此方法像Promise.resolve() 一样工作,区别是被创建的 Promise 处于拒绝态
let promise = Promise.reject(42);
promise.catch(function(value) {
console.log(value); // 42
});
非 Promise 的 Thenable
Promise.resolve() 与 Promise.reject() 都能接受非 Promise 的 thenable 作为参数。当传
入了非 Promise 的 thenable 时,这些方法会创建一个新的 Promise ,此 Promise 会在
then() 函数之后被调用。
当一个对象拥有一个能接受 resolve 与 reject 参数的 then() 方法,该对象就会被认为是
一个非 Promise 的 thenable ,就像这样:
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
此例中的 thenable 对象,除了 then() 方法之外没有任何与 Promise 相关的特征。你可以
调用 Promise.resolve() 来将 thenable 转换为一个已完成的 Promise :
let thenable = {
then: function(resolve, reject) {
resolve(42);
}
};
let p1 = Promise.resolve(thenable);
p1.then(function(value) {
console.log(value); // 42
});
链式Promise
每次对 then() 或 catch() 的调用实际上创建并返回了另一个 Promise ,仅当前一个
Promise 被完成或拒绝时,后一个 Promise 才会被决议。
因此我们可以进行链式调用
let p1 = new Promise(function(resolve, reject) {
resolve(42);
});
p1.then(function(value) {
console.log(value);
return value+1
}).then(function(val) {
console.log(val);
}).catch((err)=>{
});
以上中第一个then方法会作为第二个then方法的入参,把then方法的返回值一直传递下去,Promise 链允许你捕获前一个 Promise 的完成或拒绝处理函数中发生的错误。因此只要有某个then方法出现错误,或者直接失败就会调用catch方法
在 Promise 链中返回 Promise
从完成或拒绝处理函数中返回一个基本类型值,能够在Promise之间传递数据,但若你返回的是一个对象呢?若该对象是一个 Promise ,那么需要采取一个额外步骤来决定如何处理。
let p1 = new Promise(function(resolve, reject) {
resolve(42);
});
let p2 = new Promise(function(resolve, reject) {
resolve(43);
});
p1.then(function(value) {
// 第一个完成处理函数
console.log(value); // 42
return p2;
}).then(function(value) {
// 第二个完成处理函数
console.log(value); // 43
})catch((err)=>{
});
在此代码中, p1 安排了一个决议 42 的作业, p1 的完成处理函数返回了一个已处于决议态的 Promise : p2 。由于 p2 已被完成,第二个完成处理函数就被调用了。而若p2被拒绝,会调用拒绝处理函数(如果存在的话),而不调用第二个完成处理函数。
Promise.all() 方法
Promise.all() 方法接收单个可迭代对象(如数组)作为参数,并返回一个 Promise 。这个可迭代对象的元素都是 Promise ,只有在它们都完成后,所返回的 Promise 才会被完成。
let p1 = new Promise(function(resolve, reject) {
resolve(42);
});
let p2 = new Promise(function(resolve, reject) {
resolve(43);
});
let p3 = new Promise(function(resolve, reject) {
resolve(44);
});
let p4 = Promise.all([p1, p2, p3]);
p4.then(function(value) {
console.log(Array.isArray(value)); // true
console.log(value[0]); // 42
console.log(value[1]); // 43
console.log(value[2]); // 44
});
此处前面的每个 Promise 都用一个数值进行了决议,对 Promise.all() 的调用创建了新的Promise p4 ,在 p1 、 p2 与 p3 都被完成后, p4 最终会也被完成。传递给 p4 的完成处理函数的结果是一个包含每个决议值( 42 、 43 与 44 )的数组,这些值的存储顺序保持了待决议的 Promise 的顺序(与完成的先后顺序无关),因此你可以将结果匹配到每个
Promise 。
若传递给 Promise.all() 的任意 Promise 被拒绝了,那么方法所返回的 Promise 就会立刻被拒绝,而不必等待其他的 Promise 结束
也就是说只要数组里面的promise有一个执行失败,Promise.all()就会立马执行失败决议,调用catch()方法
Promise.race() 方法
Promise.race()跟Promise.all()方法入参都一样,只是Promise.race()是只要有一个Promise执行成功决议,Promise.race()就执行成功决议
这两种方法十分类似于数组的every()方法和some()方法
继承 Promise
正像其他内置类型,你可将一个Promise用作派生类的基类。这允许你自定义变异的Promise,在内置Promise的基础上扩展功能。例如,假设你想创建一个可以使用success()与failure()方法的Promise,对常规的then()与catch()方法进行扩展,可以像下面这样创建该 Promise 类型:
class MyPromise extends Promise {
// 使用默认构造器
success(resolve, reject) {
return this.then(resolve, reject);
}
failure(reject) {
return this.catch(reject);
}
}
let promise = new MyPromise(function(resolve, reject) {
resolve(42);
});
promise.success(function(value) {
console.log(value); // 42
}).failure(function(value) {
console.log(value);
});
可以封装自己的Promise哦!
总结
Promise 被设计用于改善 JS 中的异步编程,与事件及回调函数对比,在异步操作方面为你提供了更多的控制权与组合性。 Promise 调度被添加到 JS 引擎作业队列,以便稍后执行。不过此处有另一个作业队列追踪着Promise的完成与拒绝处理函数,以确保适当的执行。
Promise 具有三种状态:挂起、已完成、已拒绝。一个Promise起始于挂起态,并在成功时转为完成态,或在失败时转为拒绝态。在这两种情况下,处理函数都能被添加以表明Promise何时被解决。then()方法允许你绑定完成处理函数与拒绝处理函数,而 catch()方法则只允许你绑定拒绝处理函数。
你能用多种方式将多个 Promise 串联在一起,并在它们之间传递信息。每个对 then() 的调用都创建并返回了一个新的 Promise ,在前一个 Promise 被决议时,新Promise也会被决议。Promise链可被用于触发对一系列异步事件的响应。你还能使用 Promise.race() 与Promise.all() 来监视多个 Promise 的进程,并进行相应的响应。
组合使用生成器与 Promise 会让异步任务运行得更容易,这是由于Promise提供了异步操作可返回的一个通用接口。这样你就能使用生成器与 yield 运算符来等待异步响应,并作出适当的应答。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。