Promise和Async的用法整理

1.Promise

1.简介

Promise,简单来说就是一个容器,里面保存着某个未来才会结束的时间(通常是一个异步操作的结果)

Promise对象的基本语法:

new Promise((resolve,reject) => {
    //.....
});

从语法上来说,Promise是一个对象,从它可以获取异步操作的消息。

基本语法:

let p = new Promise((resolve,reject) => {
    //...
    resolve('success')
});

p.then(result => {
    console.log(result);//success
});

Promise对象特点和三个状态:

image

例如:

let p = new Promise((resolve,reject) => {
    //...
    resolve('success');
    console.log('after resolve');
    reject('error');
});

p.then(result => {
    console.log(result);
});

p.catch(result => {
    console.log(result);
})

运行结果:
after resolve
success

resolve下面的语句其实是可以执行的,那么为什么reject的状态信息在下面没有接受到呢?这就是因为Promise对象的特点:状态的凝固。new出一个Promise对象时,这个对象的起始状态就是Pending状态,在根据resolve或reject返回Fulfilled状态/Rejected状态。

2.

image

Then分别接受resolve和reject的信息,有三种参数形式,第三种比较“怪异”,只用来接收做reject处理。

eg:

let p = new Promise((resolve,reject) => {
    //...
    let random = Math.random();//小于1大于0
    if(random > 0.4) {
        resolve('random > 0.4');
    }else {
        reject('random <= 0.4');
    }
});

p.then(result => {
    console.log('resolve',result);
}, result => {
    console.log('reject',result);
});

3.链式调用

我们来执行一段代码:

let p = new Promise((resolve,reject) => {
    reject('reject');
});

let resultP = p.then(null,result => {
    console.log(result);
});

console.log(resultP);

结果:
Promise { <pending> }
reject

js的执行顺序就是这样,同步->异步->回调,在同步执行的时候,Promise对象还处于pending的状态,也说明了这个then返回的是一个Promise对象。

而且必须在then里面给一个返回值,才能继续调用,否则undefined。
eg:

let p = new Promise((resolve,reject) => {
    reject('error');
});

let resultP = p.then(null,result => {
    console.log(result);
    return 123;
});

// console.log(resultP);
resultP.then(tmp => {
    console.log(tmp);
})

结果:
error
123

4.catch

image

eg:

let p = new Promise((resolve,reject) => {
    reject('error');
});

p.catch(result => {
    console.log(result);
})

那这个catch的返回值是什么呢:
和上面then是一样的。

5.Promise.resolve()

image

传一个普通的对象:

// let p1 =Promise.resolve(123);
let p1 =Promise.resolve({name:'xixi',age:'xxxx'});

p1.then(result => {
    console.log(result);
});

如果是Promise对象呢,直接返回

let p = new Promise((resolve,reject) => {
    setTimeout(() => {
        resolve('success');
    },500);
});

let pp = Promise.resolve(p);

pp.then(result => {
    console.log(result);
});

console.log(pp == p);

结果:
true
success

6.Promise.reject()

image

eg:

let p = Promise.reject(123);

console.log(p);

p.then(result => {
    console.log(result);
}).catch(result => {
    console.log('catch',result);
})

结果:
Promise { <rejected> 123 }
catch 123

7.Promise.all()

image

eg:

let p1 = Promise.resolve(123);
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('success');

Promise.all([p1,p2,p3]).then(result => {
    console.log(result);
})

结果:
[ 123, 'hello', 'success' ]

成功之后就是数组类型,当所有状态都是成功状态才返回数组,只要其中有一个的对象是reject的,就返回reject的状态值。
eg:

let p1 = Promise.resolve(123);
let p2 = Promise.resolve('hello');
let p3 = Promise.resolve('success');
let p4 = Promise.reject('error');

// Promise.all([p1,p2,p3]).then(result => {
//     console.log(result);
// });

Promise.all([p1,p2,p4]).then(result => {
    console.log(result);
}).catch(result => {
    console.log(result);
});

结果:
error

又一个eg:

//用sleep来模仿浏览器的AJAX请求
function sleep(wait) {
    return new Promise((res,rej) => {
        setTimeout(() => {
            res(wait);
        },wait);
    });
}

let p1 = sleep(500);
let p2 = sleep(500);
let p3 = sleep(1000);

Promise.all([p1,p2,p3]).then(result => {
    console.log(result);
    //.....
    //loading
});

8.Promise.race

image

和all同样接受多个对象,不同的是,race()接受的对象中,哪个对象返回的快就返回哪个对象,就如race直译的赛跑这样。如果对象其中有reject状态的,必须catch捕捉到,如果返回的够快,就返回这个状态。race最终返回的只有一个值。
eg:

//用sleep来模仿浏览器的AJAX请求
function sleep(wait) {
    return new Promise((res,rej) => {
        setTimeout(() => {
            res(wait);
        },wait);
    });
}

let p1 = sleep(500);
let p0 = sleep(2000);

Promise.race([p1,p0]).then(result => {
    console.log(result);
});

let p2 = new Promise((resolve,reject) => {
    setTimeout(()=>{
        reject('error');
    },1000);
});

Promise.race([p0,p2]).then(result => {
    console.log(result);
}).catch(result => {
    console.log(result);
});

500
error

9.异常处理

image

为什么说安静,一个例子,Pormise内部的错误外界用try-catch捕捉不到
eg:

try {
    let p = new Promise((resolve, reject) => {
        throw new Error("I'm error");
        // reject(new Error("I'm Error"));
    });
}catch(e) {
    console.log('catch',e);
}

结果什么都没打印。
但是抛出的错误可以通过catch来捕捉:

// try {
    let p = new Promise((resolve, reject) => {
        throw new Error("I'm error");
        // reject(new Error("I'm Error"));
    });
// }catch(e) {
//     console.log('catch',e);
// }

p.catch(result => {
    console.log(result);
});

这样就捕捉到错误。所以:

image

2.Async-Await

1.简介:

image
image

async和await在干什么,async用于申明一个function是异步的,而await可以认为是async wait的简写,等待一个异步方法执行完成。

2.基本语法

image

在Chrome里申明这样一个函数,可以在控制台看到返回的其实就是一个Promise对象。
扩展需要了解的就是Chrome现在也支持asyncFunction,可以在Chrome控制台测试:
console.log(async function(){}.constructor);
ƒ AsyncFunction() { [native code] }

3.规则

image

如图,await放在普通函数里是会报错的。

image

eg:

async function demo() {
    let result = await Promise.resolve(123);
    console.log(result);
}
demo();

4.应用

Promise虽然一方面解决了callback的回调地狱,但是相对的把回调“纵向发展”了,形成了一个回调链。eg:

function sleep(wait) {
    return new Promise((res,rej) => {
        setTimeout(() => {
            res(wait);
        },wait);
    });
}

/*
let p1 = sleep(100);
let p2 = sleep(200);
let p =*/

sleep(100).then(result => {
    return sleep(result + 100);
}).then(result02 => {
    return sleep(result02 + 100);
}).then(result03 => {
    console.log(result03);
})

控制台:
300

后面的结果都是依赖前面的结果。
改成async/await写法就是:

async function demo() {
    let result01 = await sleep(100);
    //上一个await执行之后才会执行下一句
    let result02 = await sleep(result01 + 100);
    let result03 = await sleep(result02 + 100);
    // console.log(result03);
    return result03;
}

demo().then(result => {
    console.log(result);
});

因为async返回的也是promise对象,所以用then接受就行了。
结果:
300
需要注意的就是await是强制把异步变成了同步,这一句代码执行完,才会执行下一句。

5.错误处理

image

如果是reject状态,可以用try-catch捕捉
eg:

let p = new Promise((resolve,reject) => {
    setTimeout(() => {
        reject('error');
    },1000);
});

async function demo(params) {
    try {
        let result = await p;
    }catch(e) {
        console.log(e);
    }
}

demo();

结果:
error
这是基本的错误处理,但是当内部出现一些错误时,和上面Promise有点类似,demo()函数不会报错,还是需要catch回调捕捉。这就是内部的错误被“静默”处理了。

let p = new Promise((resolve,reject) => {
    setTimeout(() => {
        reject('error');
    },1000);
});

async function demo(params) {
    // try {
        let result = name;
    // }catch(e) {
    //     console.log(e);
    // }
}

demo().catch((err) => {
    console.log(err);
})

6.注意你的并行执行和循环

比如上面的例子:

image

如果这三个是你想异步发出的AJAX请求,在这段代码里其实是同步的,第一个发出去才会发第二个,所以async/await需要谨慎使用。

image

现在有一些forEach或者map的循环里,比如在forEach里使用await,这时候的上下文就变成了array,而不是async function,就会报错。这时候你就要想到是什么错误。

作者:Lawliet_ZMZ
链接:https://www.jianshu.com/p/fe0159f8beb4
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

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

推荐阅读更多精彩内容