导言:在学习 async/awit之前, 我们很有必要学习一下 , 迭代器(lterator)和生成器(Generator)
迭代器(lterator)和生成器(Generator)
导言:用循环语句迭代数据时,必须要初始化有关变量来记录每一次迭代在数据集合中的位置,
迭代器的使用可以极大地简化数据操作,于是es6也向js中添加了这个迭代器特性。新的数组方法和新的集合类型(例如:Set与Map集合)都依赖迭代器的实现,甚至异步编程中都可以使用迭代器。
但这此之前,我们一定要了解一下迭代器的背后的历史。
循环语句的问题
var colors = ['red','green','blue'];
for(var i = 0 ,len = colors.length ; i < len ; i ++) {
console.log(colors[i])
}
上面是一段标准的for循环代码,通过变量i来跟踪colors数组的索引。
虽然循环语句的语法简单,但是如果将多个循环嵌套则需要追踪多个变量,代码的复杂度会大大增加。迭代器的出现为了消除这种复杂性并减少循环中的错误。
什么是迭代器
迭代器是一种特殊对象,它具有一些专门为迭代过程设计的专有接口,所有的迭代器对象都有一个next()方法,每次调用都返回一个结果对象。结果对象有两个属性:一个是value,表示下一个将要返回的值;另一个是done, 它是一个布尔类型的值,当没有更多可返回数据时返回数据时返回true。迭代器还会保存一个内部指针,用来指向当前集合中值的位置,每调用一次next()方法,都会返回下一个可用的值。
我们用es5的语法来自己写一个迭代器
按我的理解,这应该属于闭包的用处
function createIterator(items) {
var i = 0;
return {
next :function() {
var done = ( i >= items.length);
var value = !done ? items[i++] :undefined;
return {
done : done,
value : value
}
}
}
}
var iterator = createIterator([1,2,3]);
console.log(iterator.next()) //{ done: false, value: 1 }
console.log(iterator.next()) //{ done: false, value: 2 }
console.log(iterator.next()) //{ done: false, value: 3 }
console.log(iterator.next()) //{ done: true, value: undefined }
console.log(iterator.next()) //{ done: true, value: undefined }
迭代器的编写规则也同样复杂,但es6同时还引入一个生成器对象,它可让创建迭代器对象过程变得简单。
note: 检测对象是否为可迭代对象
function isIterable(object) {
return typeof object[Symbol.iterator] === "function";
}
什么是生成器
生成器是一种返回迭代器的函数,通过 function 关键字后的 星号(*)来表示, 函数中会用到新的关键字 yield 。就像这样 :
//生成器
function *createIterator() {
yield 1;
yield 2;
yield 3;
}
// 生成器的调用方式与普通函数相同, 只不过返回的是一个迭代器
let iterator = createIterator();
console.log(iterator.next())//{ value: 1, done: false }
console.log(iterator.next())//{ value: 2, done: false }
console.log(iterator.next())//{ value: 3, done: false }
console.log(iterator.next())//{ value: undefined, done: true }
在这个实例中, createIterator()前的星号表明它是一个生成器;yield 关键字也是 es6的新特性 , 可用通过它来指定调用迭代器的 next()方法时的返回值及返回顺序。生成迭代器后, 连续3次调用它的next()方法返回3个不同的值 , 分别是 1,2,3。 生成器的调用过程与其他函数一样 , 最终返回的是创建好的迭代器。
生成器函数最重要的是,每当执行完一条 yield 语句后函数就会自动停止执行.
异步任务执行
生成器令人兴奋的特性多与异步编程有关, javaScript中的异步编程有利有弊:简单任务的异步化非常容易实现;而复杂任务的异步化会带来很多管理代码的挑战。由于生成器支持在函数中暂停代码执行,因而可以深入挖掘异步处理的更多用法。如果需要嵌套回调化序列化一系列的异步操作,事情会变得非常复杂。此时,生成器和yield语句就派上用场了。
简单任务执行器
由于执行yield 语句会暂停当前函数的执行过程并等待下一次调用 next()方法。因此你可以创建一个函数,在函数中调用生成器生成相应的迭代器,从而在不用回调函数的基础上实现异步调用next()方法,就像这样:
function run(taskDef) {
// 创建一个无使用限制的迭代器
let task = taskDef();
// 开始执行任务
let result = task.next();
//循环调用next()的函数
function step() {
// 如果任务未完成,则继续执行
if(!result.done) {
result = task.next();
step();
}
}
//开始迭代执行
step();
}
// 执行
run(function *() {
console.log(1);
yield;
console.log(2);
yield;
console.log(3)
})
函数run()接收一个生成器函数作为参数,这个函数定义了后续要执行的任务,生成一个迭代器并将它存储其在变量task中。首次调用迭代器的next()方法时,返回的结果被存储起来稍后继续使用。step()函数会检查result.done的值,如果为false则执行迭代器的next()方法,并再次执行step()操作。每次调用next()方法,返回的最新信息总是覆盖变量result。在代码的最后,初始化执行step()函数并开始整个的迭代过程,每次通过检查result.done来确定是否有更多任务需要执行。
向任务执行器传递数据
给任务执行器传递数据的最简单方法是,将值通过迭代器的next()方法传入作为yield的生成值供下次调用。这下面这段代码中,只需要将result.value传入next()方法即可:
function run(taskDef) {
// 创建一个无使用限制的迭代器
let task = taskDef();
//开始执行任务
let result = task.next();
// 循环调用next()的函数
function step() {
//如果任务未完成 , 则继续执行
if(!result.done) {
result = task.next(result.value);
step();
}
}
//开始迭代执行
step();
}
run(function *() {
let value = yield 1;
console.log(value); // 1
value = yield value + 3;
console.log(value);
})
这例子会向控制台输出两个数值 1 和 4.
现在数据已经能够在yield调用间互相传递了,只需要一个小小的改变便能支持异步调用。
异步任务执行器
之前的例子只是在多个yield调用间来回传递静态数据,而等待一个异步过程有些不同。任务执行器需要知晓回调函数是什么以及如何使用它。由于 yield表达式会将值返回给任务执行器,所有的函数调用都会返回一个值,因此在某种程度上这也是一个异步操作,任务执行器会一直等待直到操作完成。
下面我们定义一个异步操作:
function fetchData() {
return function(callback) {
setTimeout(function() {
callback(null,'Hi');
}, 50)
}
}
理解了函数中异步过程的运作方式,我们可以将任务执行器稍作修改。当result.value是一个函数时,任务执行器会先执行这个函数再讲结果传入next()方法,代码更新如下 :
function run(taskDef) {
// 创建一个无使用限制的迭代器
let task = taskDef();
//开始执行任务
let result = task.next();
// 循环调用next()函数
function step() {
//如果任务未完成 , 则继续执行
if(!result.done) {
if(typeof result.value === "function") {
result.value(function(err,data) {
if(err) {
result = task.throw(err);
return;
}
result = task.next(data);
step();
});
} else {
result = task.next(result.value);
step();
}
}
}
//开始执行迭代
step();
}
通过 === 操作符检查后 , 如果 result.value 是一个函数,会传入一个回调函数作为参数来调用它,回调函数遵循node.js中有关执行错误的约定;所可能的错误放在第一个参数(err)中,结果放在第二个参数中。如果传入了err,则意味着执行过程中产生了cuow,这时会通过task.throw()正确输出错误对象。如果 result.value 不是一个函数,则直接将其传入next()方法。
现在,这个新版的任务执行器已经可以用于所有的异步任务了。在node.js环境中,如果要从文件中读取一些数据,需要在fs.readFile()外围创建一个包装器(wrapper), 返回一个与 fetchData()类似的函数
let fs = require('fs');
function readFile(filename) {
return function(callback) {
fs.readFile(filename,'utf8',callback);
}
}
//调用
run(function *(){
let contents = yield readFile('1.txt');
console.log(contents);
})
Promise与异步编程
哎,我们终于开始学习Promise了,接一来,我们将学
- Promise出现的原因是什么
- Promise是什么
- Promise的基本概念
- 最后我们将亲自手写一个简单的Promise
异步编程背景知识
javaScript引擎是基于单线程和事件循环的概念构建的,同一时刻只允许一个代码块执行。
Promise出现的原因
那么,如果我们有一天必须控制 两段异步操作的执行顺序时,我们该怎么办呢?
比如,我们必须先 读1.txt文件 , 再复制一份 2.txt文件。
我们知道 , I/O操作都是异步的 , 控制顺序的话,我们可以这样:
fs.readFile('./1.txt','utf8',(err,data)=>{
fs.writeFile('./2.txt',data,(err)=>{
if(err) {
return;
}
})
})
简单来说,就是把写的操作放在读的里面来执行。但这样不太好,因为一旦要操作异步的顺序的代码多了起来,一旦不知道哪里出了 bug ,就会很难调试,看的头都会大。
Promise是什么
Promise是一种异步操作的解决方案,将写法复杂的传统的回调函数和监听事件的异步操作,用同步代码的形式表达出来。避免了多级异步操作的回调函数嵌套。
Promise的基本概念
Promise相当于异步操作结果的占位符,它不会订阅一个事件,也不会传递一个回调函数给目标函数,而是让函数返回一个Promise
Promise的生命周期
每个Promise都会经历一个短暂的生命周期 :先是处于进行中(pending)的状态,此时操作尚未完成,所以它也是未处理(unsettled)的;一但异步操作执行结束,Promise在变成下面其中一个:
- Fulfilled Promise异步操作成功完成
- Rejected 由于程序错误或一些其他原因,Promise异步操作未能成功完成。
note:如果一个对象实现了then()方法,那这个对象我们称之为 thenable 对象。所有的Promise都是thenable对象,但并非所有thenable对象都是Promise.
有了Promise,我们便可以将上面的读写操作,变成下面这样了:
//读
function readPath(path) {
return new Promise((resolve,reject)=>{
fs.readFile(path,'utf8',(error,data)=>{
if(error) {
reject(error);
} else {
resolve(data)
}
})
})
}
//写
function wirtePath(path,data) {
return new Promise((resolve,reject)=>{
fs.writeFile(path,data,(error)=>{
if(error) {
reject(error)
} else {
resolve('success')
}
})
})
}
readPath('./1.txt')
.then((data)=>{
wirtePath('./2.txt',data);
},(reason)=>{
console.log(reason);
})
更好的异步任务执行: 其基本思想为
用 async 标记的函数 代替生成器 , 用 await 代替 yield 来调用函数,就像这样
async function (){
let content = await readPath('./1.txt');
let msg = await wirtePath('./2.txt',content);
console.log(msg)
}() // 这里是自执行函数
手写Promise
我们觉得与其看各种各样的Promise面试题,都不如先实现一下Promise,明白了原理,自然更容易知道怎么用 现在,我们开始这篇文章的压轴代码,实现一个简单的Promise,
Promise的声明
首先,Promise肯定是一个类,我们就用 class 来声明
- 由于 new Promise((resolve,reject) => {}),所以传入的参数是一个函数,我们叫他 executor ,传入就执行
- executor 里面有两个参数 , 一个叫 resolve(成功),一个叫 reject(失败)
-
由于 resolve 和 reject 可执行 , 所以都是函数 , 我们用let 声明
class Promise {
constructor(executor) { // 成功 let resolve = (value) => {}; // 失败 let reject = (reason) => {}; }
}
解决基本状态
对Promise的规定
- Promise存在三种状态 (state) pending ,fulfilled ,rejected
- pending (等待状态)为初始状态 ,并可以转化为 fulfilled(成功状态) 和 rejected(失败状态)
- 成功时 , 不可转为其他状态 , 并且必须有一个不可改变的值 (value)
- 失败时 , 不可转为其他状态 , 并且必须有一个不可改变的原因(reason)
- new Promise((resolve, reject)=>{resolve(value)}) resolve为成功,接收参数value,状态改变为fulfilled,不可再次改变。
- new Promise((resolve, reject)=>{reject(reason)}) reject为失败,接收参数reason,状态改变为rejected,不可再次改变。
-
若是executor函数报错 直接执行reject();
class Promise {
constructor(executor) { //初始化 state 为等待状态 this.state = 'pending'; // 成功的值 this.value = undefined; // 失败的值 this.reason = undefined; let resolve = (value) => { // state 改变 , resolve 调用会失败 if(this.state === 'pending') { this.state = 'fulfilled';// 调用 resolve后,state转化为成功状态 this.value = value;// 存储成功的值 } }; // 失败 let reject = (reason) => { //state 改变后, reject 调用就会失败 if(this.state === 'pending') { // reject 调用后, state 转化为失败状态 this.state = 'rejected'; this.reason = reason;// 存储失败的原因 } }; // 立即执行 // 如果 executor 执行报错 , 直接执行 reject try { executor(resolve,reject); } catch (err) { reject(err); } }
}
then方法
规定 : Promise有一个叫做then的方法 , 里面有两个参数 :onFulfilled , onRejected ,成功有成功的值 ,失败有失败的原因
- 当状态state为 fulfilled ,则执行 onFulfilled , 传入this.value .当状态 state为 rejected , 则执行 onRejected , 传入this.reason
-
onFulfilled, onRejected 如果他们是函数, 则必须分别在 fulfilled , rejected 后被调用 , value 或 reason 依次作为他们的第一个参数
then(onFulfilled,onRejected) {
// 状态为 fulfilled , 执行 onFulfilled , 传入成功的值 if(this.state === 'fulfilled') { onFulfilled(this.value); }; // 状态为rejected , 执行onRejected , 传入失败的原因 if(this.state === 'rejected') { onRejected(this.reason); }
}
解决异步问题
现在基本可以实现简单的同步代码 ,但是当 resolve在setTimeout 内执行 , then 时state还是pending等待状态 , 我们就需要在 then调用的时候 , 将成功和失败存到各自的数组 , 一旦 reject 或者 resolve ,就调用他们。
类似于发布订阅 , 先将then里面的两个函数存储起来 , 由于一个 Promise可以有多个 then , 所以存在同一个数组内。
// 手写Promise
class Promise {
constructor(executor) {
//初始化状态
this.state = 'pending';
// 成功值
this.value = undefined;
// 失败值
this.reason = undefined;
// 成功存放的数组
this.onResolvedCallbacks = [];
// 失败存放的数组
this.onRejectedCallbacks = [];
// 成功
let resolve = (value) => {
// state 改变 , resolve 调用
if(this.state === 'pending') {
this.state = 'fulfilled';// 调用 resolve 后 , state转换为成功状态
this.value = value;//存储成功的值
// 一旦resolve 执行, 调用成功数组的函数
this.onResolvedCallbacks.forEach(fn => fn());
}
}
// 失败
let reject = (reason) => {
if(this.state === 'pending') {
this.state = 'rejected';
this.reason = reason;
// 一旦 resolve执行 , 调用失败数组的函数
this.onRejectedCallbacks.forEach(fn => fn());
}
}
try {
executor(resolve,reject);
} catch (error) {
reject(error)
}
}
then(onFulfilled,onRejected) {
// 状态为 fulfilled , 执行 onFulfiiled , 传入成功的值
if(this.state === 'fulfilled') {
onFulfilled(this.value);
};
//状态为 rejected , 执行onRejected , 传入失败的原因
if(this.state === 'rejected') {
onRejected(this.reason);
}
// 当状态为 pending时
if(this.state === 'pending') {
// onFulfilled 传入到成功数组中
this.onResolvedCallbacks.push(()=>{
onFulfilled(this.value);
})
// onRejected 传入到失败数组
this.onRejectedCallbacks.push(()=>{
onRejected(this.reason);
})
}
}
catch() {
}
}
解决链式调用
我们常常用到的 new Promise().then().then(),这就是链式调用,用来解决回调地狱的问题。
- 为了达成链式 , 我们默认在第一个then里返回一个Promise.
规定 : 在then里面返回一个新的Promise , 称为promise2;
promise2 = new Promise((resolve,reject)=>{})
- 将这个promise2 返回的值传递到下一个then中
- 如果返回一个普通的值 , 则将普通的值传递给下一个then中
- 当我们在第一个then中 return 了一个参数(参数未知,需要判断)。这个return 出来的新的promise就是 onFulfilled()或 onRejected()的值。
规定 : onFulfilled()或 onRejected()的值 , 即第一个then返回的值 , 叫做 x ,判断 x 的函数叫做 resolvePromise
- 首先 , 要看 x 是不是 promise
- 如果是promise , 则取它的结果 , 作为新的 promise2
- 如果是普通值 , 直接作为 promise2 成功的结果
- 所以要比较 x 和 promise2
- resolvePromise 的参数有 promise2 (默认返回的 promise) , x(我们自己 return 的对象) , resolve , reject
-
resolve 和 reject 是promise2的
class Promise {
constructor(executor) { //初始化状态 this.state = 'pending'; // 成功值 this.value = undefined; // 失败值 this.reason = undefined; // 成功存放的数组 this.onResolvedCallbacks = []; // 失败存放的数组 this.onRejectedCallbacks = []; // 成功 let resolve = (value) => { // state 改变 , resolve 调用 if (this.state === 'pending') { this.state = 'fulfilled';// 调用 resolve 后 , state转换为成功状态 this.value = value;//存储成功的值 // 一旦resolve 执行, 调用成功数组的函数 this.onResolvedCallbacks.forEach(fn => fn()); } } // 失败 let reject = (reason) => { if (this.state === 'pending') { this.state = 'rejected'; this.reason = reason; // 一旦 resolve执行 , 调用失败数组的函数 this.onRejectedCallbacks.forEach(fn => fn()); } } try { executor(resolve, reject); } catch (error) { reject(error) } } then(onFulfilled, onRejected) { // 声明返回的 promise2 let promise2 = new Promise((resolve, reject) => { // 状态为 fulfilled , 执行 onFulfiiled , 传入成功的值 if (this.state === 'fulfilled') { let x = onFulfilled(this.value); // resolvePromise 函数 , 处理自己 return 的 promise和 默认的 promise2的关系 resolvePromise(promise2, x, resolve, reject); }; //状态为 rejected , 执行onRejected , 传入失败的原因 if (this.state === 'rejected') { let x = onRejected(this.reason); resolvePromise(promise2, x, resolve, reject); } // 当状态为 pending时 if (this.state === 'pending') { // onFulfilled 传入到成功数组中 this.onResolvedCallbacks.push(() => { let x = onFulfilled(this.value); resolvePromise(promise2,x,resolve,reject); }) // onRejected 传入到失败数组 this.onRejectedCallbacks.push(() => { let x = onRejected(this.reason); resolvePromise(promise2,x,resolve,reject); }) } }); // 返回promise2 , 完成链式 return promise2; }
}
完成 resolvePromise函数
规定 : 一段代码 , 让不同的promise代码互相套用 , 叫做resolvePromise
-
如果 x === promise2 , 则是会造成循环引用 , 自己等待自己完成 ,则报 "循环引用" 错误。
function resolvePromise(promise2,x,resolve,reject) {
if(x === promise2) { return reject(new TypeError('Chaining cycle detected for promise')); }
}
- 判断 x
- 如果 x 是一个对象或者函数 , 则设为 x
- x 不能是 null
- x 是普通值 , 则直接 resolve(x)
- x 是对象或者函数 (包括promise), let then = x.then;
- 声明了 then
- 如果取 then 报错 , 则走 reject()
- 如果 then是个函数 , 则用 call执行then , 第一个参数是this ,后面是成功的回调和失败的回调
- 如果是成功的回调还是promise ,就继续递归
- 成功和失败只能调用一个 , 所以设定一个 called来防止多次调用。
note : 这个方法是 Promise 原码的精髓 , 可以仔细看看
// 完成 resolvePromise函数
function resolvePromise(promise2, x, resolve, reject) {
// 循环引用报错
if (x === promise2) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
//防止多次调用
let called;
// x不是null 并且 x是对象或者函数
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// A+ 规定 , 声明 then = x 的 then 方法
let then = x.then;
//如果 then 是函数 , 就默认是promise 了
if (typeof then === 'function') {
// 就让 then 执行 第一个参数是 this 后面是成功的回调 和失败的回调
then.call(x, y => {
// 成功和失败只能调用一个
if (called) return;
called = true;
// resolve 就结果依旧是 promise 那就继续解析
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失败只能调用一个
if (called) return;
called = true;
reject(err);
})
} else {
resolve(x); // 直接成功即可
}
} catch (e) {
// 也属于失败
if(called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
其他问题
- 规定 : onFulfilled , onRejected 都是可选参数 , 如果他们不是函数 , 必须被忽略
- onFulfilled返回一个普通的值 , 成功时直接等于 value => value
- onRejected 返回一个普通的值 , 失败时如果直接等于 value => value, 则会跑到下一个 then中的 onFulfilled 中 , 所以直接扔出一个错误 err => throw err
- 规定 onFulfilled 或 onRejected 不能同步被调用 , 必须异步调用。我们就用 setTimeout解决异步问题
- 如果onFulfilled 或 onRejected报错 , 则直接返回 reject()
最终版本
可以 look a look
// 手写Promise
class Promise {
constructor(executor) {
// 初始化state 为等待状态
this.state = 'pending';
// 成功的值
this.value = undefined;
// 失败的值
this.reason = undefined;
// 成功存放的数组
this.onResolvedCallbacks = [];
// 失败存放的数组
this.onRejectedCallbacks = [];
// 成功
let resolve = (value) => {
// state 改变 , resolve 调用的会失败
if (this.state === 'pending') {
this.state = 'fulfilled'; // resolve调用后 , state转化为成功态
this.value = value;// 存储成功的值
// 一旦resolve执行 , 调用成功数组的函数
this.onResolvedCallbacks.forEach(fn => fn());
}
}
// 失败
let reject = (reason) => {
// state改变后 , reject调用就会失败
if (this.state === 'pending') {
// reject 调用后 , state 转换为失败状态
this.state = 'rejected';
this.reason = reason;// 存储失败的原因
// 一旦reject 执行 , 调用失败数组的函数
this.onRejectedCallbacks.forEach(fn => fn());
}
};
// 立即执行
// 如果 executor 执行报错 , 直接执行 reject
try {
executor(resolve, reject)
} catch (err) {
reject(err)
}
}
then(onFulfilled, onRejected) {
// onFulfilled 如果不是函数 , 就忽略 onFulfilled , 直接返回 value
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
// onRejected 如果不是函数 , 就忽略 onRejected , 直接扔出错误
onRejected = typeof onRejected === "function" ? onRejected : err => { throw err };
// 声明返回的 promise2
let promise2 = new Promise((resolve, reject) => {
if (this.state === 'fulfilled') {
// 异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
// resolvePromise函数 , 处理自己return 的promise和默认的promise2的关系
resolvePromise(promise2, x ,resolve,reject);
} catch (e) {
reject(e);
}
},0)
};
if (this.state === 'rejected') {
//异步
setTimeout(() => {
// 如果报错
try {
let x = onRejected(this.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e);
}
},0);
};
// 当状态state为pending 时
if (this.state === 'pending') {
// onFulfilled传入到成功数组
this.onResolvedCallbacks.push(() => {
//异步
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2,x , resolve,reject);
} catch (e) {
reject(e)
}
},0);
})
// onRejected 传入到失败数组
this.onRejectedCallbacks.push(() => {
// 异步
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2,x,resolve,reject);
} catch (e) {
reject(e)
}
})
})
}
});
// 返回promise , 完成链式
return promise2;
}
catch(fn) {
return this.then(null,fn);
}
}
function resolvePromise(promise2, x, resolve, reject) {
if (x === promise2) {
return reject(new TypeError("Chaining cycle detected for promise"));
}
// 防止多次调用
let called;
// x 不是 null 并且 x 是对象或者函数
if (x != null && (typeof x === 'object' || typeof x === 'function')) {
try {
// A+ 规定 , 声明 then = x 的then 方法
let then = x.then;
// 如果 then 是函数 , 就默认是 promise了
if (typeof then === 'function') {
// 就让 then 执行 第一个参数是 this 后面是成功的回调和 失败的回调
then.call(x, y => {
// 成功和失败只能调用一个
if (called) return;
called = true;
// resolve 的结果依旧是 promise 那就继续解析
resolvePromise(promise2, y, resolve, reject);
}, err => {
// 成功和失败只能调用一个
if (called) return;
called = true;
reject(err); // 失败了就失败了
})
} else {
resolve(x); //直接成功即可
}
} catch (e) {
// 也属于失败
if (called) return;
called = true;
// 取then出错了 那就不要再继续执行了
reject(e);
}
} else {
resolve(x);
}
}
当然, 这里还有一些挂在 Promise上的方法
// resolve方法
Promise.resolve = function(val) {
return new Promise((resolve,reject)=>{
resolve(val)
})
}
// reject方法
Promise.reject = function(val) {
return new Promise((resolve,reject)=> {
reject(val);
})
}
// all 方法 (获取所有的promise , 都执行then , 把结果放到数组 , 一起返回, 如果其中有一个发送了reject ,
则取出失败的时候最先被reject失败状态的值)
// 这个方法比较常用 , 一般用于 并发请求数据 ,ajax并发请求数据
Promise.all = function(promises) {
let arr = [];
let i = 0;
functionData(index,data) {
arr[index] = data;
i++;
if(i == promises.length) {
resolve(arr);
}
}
return new Promise((resolve,reject) => {
for(let i = 0 ; i < promises.length ; i ++) {
promises[i].then(data => {
processData(i,data);
},reject)
}
})
}
// race方法
// mdn的解释:
Promise.race()一旦可迭代的promise中的一个承诺实现或拒绝,该方法就会返回一个承诺,该承诺中包含承诺的价值或原因。
// 还是比较好理解的
Promise.race = function(promises) {
return new Promise((resolve,reject) =>{
for(let i = 0 ; i < promises.length ; i++) {
promises[i].then(resolve,reject);
}
})
}
// 用法大概是下面这样了
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功了')
}, 1000);
})
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 900);
})
Promise.race([p1, p2]).then((result) => {
console.log(result) // success
})
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。