Promise总结

手写Promise

Promise有三个状态:pending,fulfilled,rejected
Promise属性:length(恒为1),prototype
Promise方法:all,race,any,allSettled,resolve,reject
Promise原型上的属性:constructor
Promise原型上的方法:then,catch,finally

(1)Promise只接受一个参数new Promise( function(resolve, reject) {...} /* executor */ );。其中resolve和reject可以任意定义,不过executor中就必须用新定义的名字来作为resolve和reject。

new Promise((a,b)=>a(1));//Promise {<fulfilled>: 1}
new Promise((a,b)=>console.log(1));//1 Promise {<pending>}
new Promise((a,b)=>1);//Promise {<pending>}

(2)第二种情况表明:只要定义了Promise,即使无返回值也会默认返回Promise {<pending>}。第三种情况表明:返回原始数据会被直接转化为Promise {<pending>}
(3).then() 第一个参数必然是处理 resolve ,第二个参数必然是处理 reject

new Promise((a,b)=>a(1))
.then((res)=>console.log('resolve'),(rej)=>console.log('reject'))
//resolve Promise {<fulfilled>: undefined}
new Promise((a,b)=>b(1))
.then((res)=>console.log('resolve'),(rej)=>console.log('reject'))
//reject Promise {<fulfilled>: undefined}
//最后返回的 Promise {<fulfilled>: undefined} 原因参考下面 MDN 引用

第一个Promise函数返回一个fulfilled状态,then 接收后触发第一个回调函数,输出 'resolve' ,不返回值,因此等于返回一个fulfilled状态的 Promise 。
第二个Promise函数返回一个rejected状态,then 接收后触发第二个回调函数,输出 'reject' ,同样不返回值,因此也等于返回一个fulfilled状态的 Promise 。

MDN 中 .then 返回不同值时的情况:
1.返回了一个值,那么 then 返回的 Promise 将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
2.没有返回任何值,那么 then 返回的 Promise 将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined。
3.抛出一个错误,那么 then 返回的 Promise 将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
4.返回一个已经是接受状态的 Promise,那么 then 返回的 Promise 也会成为接受状态,并且将那个 Promise 的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
5.返回一个已经是拒绝状态的 Promise,那么 then 返回的 Promise 也会成为拒绝状态,并且将那个 Promise 的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
6.返回一个未定状态(pending)的 Promise,那么 then 返回 Promise 的状态也是未定的,并且它的终态与那个 Promise 的终态相同;同时,它变为终态时调用的回调函数参数与那个 Promise 变为终态时的回调函数的参数是相同的。

(4).catch() 只捕获 reject 状态,如果没有则不执行,如果 .then() 提前捕获了 reject ,并且返回了 resolve 状态(参考上面 .then() 返回不同值的结果),则 .catch() 不执行,因此不推荐 .then() 中捕获 reject ,直接用 .catch() 捕获不容易发生错误。

new Promise((resolve,reject)=>reject(1))//此处返回reject状态
.then((res)=>console.log('resolve'),(rej)=>console.log('reject'))//此处接受reject,无返回值=返回resolve
.then((res)=>console.log('resolve'),(rej)=>console.log('reject'))//此处接受resolve,无返回值=返回resolve
.catch(_=>console.log(_))//接收不到第一个Promise抛出的reject状态
//reject resolve Promise {<fulfilled>: undefined}

(5).finally() 不论什么情况一定会触发,用来结尾输出一些必须输出的东西

var isLoading = true;

new Promise((a, b) => a())
.then(_ => console.log('then'))
.finally(_ => isLoading = false);

console.log(isLoading);//false

(6)如果Promise已经resolve变成fulfilled状态,再抛出错误是无效的,如果正常抛出错误或者reject成rejected状态,除非捕获了该状态/错误,否则会一直冒泡传递。

const promise = new Promise(function(resolve, reject) {
  resolve('fulfilled');
  throw new Error('rejected');  //无效的
});
promise
  .then(function(value) { console.log(value) })//未捕获错误,第二个参数为空
  .catch(function(error) { console.log(error) });//这里未执行,代表抛出的错误是无效的
// fulfilled

(7)跟传统的try/catch代码块不同的是,如果没有使用catch()方法指定错误处理的回调函数,Promise 对象抛出的错误不会传递到外层代码,即不会有任何反应。但是尽量用catch()捕获一下错误。

const promise= function() {
  return new Promise(function(resolve, reject) {
    // 下面一行会报错,因为x没有声明
    resolve(x);  //运行到此行抛出错误,但是不会退出进程、终止脚本执行
  });
};

promise().then(function() {//此处then()未捕获reject和错误
  console.log('everything is great');
});

setTimeout(() => { console.log(123) }, 2000);  //依旧会执行
// Uncaught (in promise) ReferenceError: x is not defined
// 123

Promise的方法:
(1)Promise.all(iterable)
所有的Promise完成才完成,或参数中不再存在Promise。任意一个Promise失败,返回第一个失败的Promise.
后面需要接 then() 和 catch() 等方法接住返回的Promise。如果iterable参数中的Promise自带 catch() 捕获了错误,在all中就捕获不到reject,因为 catch() 捕获了错误之后返回的正常情况是resolve。

const p1 = new Promise((resolve, reject) => {
  resolve('hello');
})
.then(result => result)
.catch(e => e);

const p2 = new Promise((resolve, reject) => {
  throw new Error('报错了');
})
.then(result => result)
.catch(e => e);

Promise.all([p1, p2])
.then(result => console.log('then: ' + result))
.catch(e => console.log('catch: ' + e));
// then: hello,Error: 报错了  
// Promise {<fulfilled>: undefined}

(2)Promise.race(iterable)
返回一个 Promise,和第一个传递结果的 Promise 的完成方式相同。

const promise1 = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, '1');
});
const promise2 = new Promise((resolve, reject) => {
  setTimeout(resolve, 200, '2');
});
const promise3 = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, '3');
});

Promise.race([promise1, promise2, promise3]).then((value) => {
  console.log(value);//都是resolve,不过promise3更快
});
// '3'

(3)Promise.any(iterable)
接收第一个 fulfilled 状态的 Promise ,如果全部都是 rejected 状态,那么返回异步失败和 AggregateError

const pErr = new Promise((resolve, reject) => {
  reject("总是失败");
});
const pSlow = new Promise((resolve, reject) => {
  setTimeout(resolve, 500, "最终完成");
});
const pFast = new Promise((resolve, reject) => {
  setTimeout(resolve, 100, "很快完成");
});

Promise.any([pErr, pSlow, pFast]).then((value) => {
  console.log(value);
  // pFast fulfils first
})
// "很快完成"

(4)Promise.allSettled(iterable)
所有Promise都完成后,返回一个对象数组,每个对象表示对应的Promise结果。

const promise1 = Promise.resolve(3);
const promise2 = new Promise((resolve, reject) => setTimeout(reject, 100, 'foo'));
const promises = [promise1, promise2];

Promise.allSettled(promises).
  then((results) => results.forEach((result) => console.log(result.status)));

// "fulfilled"
// "rejected"

(5)Promise.resolve(value)
(6)Promise.reject(reason)

常见面试题

1.Promise如何串行链接

异步执行任务A、B、C...

  1. 使用数组的reduce方法,reduce里有四个参数,pre,next,index,arr,
  2. 如果then方法里返回的是一个promise对象,那么执行下一个then 的时候必定是在上一个then执行完之后执行

代码如下:

var createPromise = function(time) {
    return (resolve, reject)=>
    new Promise((resolve, reject)=>{
        setTimeout(()=>{
            console.log('timein'+time)
            resolve();
        }, time*1000)
    })
}
 
function serpromise(arr) {
    arr.reduce((pre, next, index, carr)=>{
        return pre.then(next)
    }, Promise.resolve())
}
 
var arr=[createPromise(2),createPromise(1),createPromise(3),createPromise(4),createPromise(5)];
// Promise.resolve().then(createPromise(2)).then(createPromise(1))
serpromise(arr)

本人才疏学浅,有错误敬请指出,感激不尽!

参考:
[1]. MDN-Promise
[2]. 【ES6基础知识】promise和await/async
[3].如何实现一个串行promise

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,265评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,078评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,852评论 0 347
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,408评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,445评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,772评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,921评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,688评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,130评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,467评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,617评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,276评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,882评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,740评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,967评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,315评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,486评论 2 348