1、什么是promise

在JavaScript中,我们经常会用到回调函数,而回调函数的使用让我们没法使用return,throw等关键字。JS引用promise正好解决了这个问题。
promise单词意思是承诺,代表未来的某个事情或者是行为。promise是一个容器,包含了异步操作。因此我们认为promise是异步操作的解决方案。所有异步操作都可以通过promise来解决

2、了解promise

上面说到promise是一个容器,那我们先在控制台打印一下。

可以看到,Promise是一个构造函数,自身就有all、reject(代表失败的回调函数, 失败的操作)、resolve(代表成功的回调函数, 成功的操作)这几个于我们而言比较眼熟的方法,原型上有then、catch等同样很眼熟的方法。这么说用Promise new出来的对象肯定就有then、catch方法。

2.1、promise对象的特点

  • Promise对象的状态不受外界影响。包含pending(进行中)、fulfilled(已成功)和rejected(已失败)三种状态。只有异步操作结果才可决定是哪种状态,其他任何操作都无法改变这种状态。
  • 一旦状态改变,就不会再变。Promise对象的状态改变,只有两种情况:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就不会再变了,这时就称为 resolved(已定型)

举个例子:

let action = new Promise(function (resolve, reject) {
// 包含一个异步操作
setTimeout(function () {
let data = Math.floor(Math.random() * 100);
console.log(data);
if (data > 50) {
resolve({
msg: '成功',
data,
});
} else {
reject({
msg: '失败',
data,
});
}
}, 30)
});
console.log(action); // pending -- 进行中
// action -- 执行完的事件

action.then(function (d) {

// 参数1 - 成功回调

console.log(action); // resolved -- 已定型(fulfilled --- 已成功)

console.log(d);

}, function (d) {

// 参数2 - 失败回调(可选)

console.log(action); // rejected -- 已失败

console.log(d);

});

输出结果:
Promise { }
52
Promise { { msg: '成功', data: 52 } }
{ msg: '成功', data: 52 }

Promise也有一些不足的地方。其一,一旦新建Promise就会立即执行,无法取消。如果不设置回调函数,Promise内部抛出的错误不会反应到外部。其二,当处于pending状态时,无法得知目前是哪个阶段。

2.2、了解宏任务和微任务

先看个例子:

console.log("a");
setTimeout(() => console.log("b")) // 回调要等到出栈才会执行
let p = new Promise((resolve, reject) => {
resolve()
console.log("c"); // 同步代码
}).then(() => {
console.log("d"); // 异步代码
})
console.log("e"); // 同步代码

输出结果:
a
c
e
d
b

总结:
宏任务指的是click,setTimeOut等DOM事件 微任务指的是promise的异步操作,数据查询
宏任务要比微任务先进栈,但是后出栈(微任务比宏任务先执行)。因此上述代码中setTimeout函数最后执行。

了解更多有关宏任务和微任务的内容

3、使用promise

3.1 异步加载图片

function loadImageAsync(url){
return new Promise(function(resolve,reject){
var image = new Image();
image.onload = function(){
resolve(this)
};
image.onerror = function(){
reject(new Error('Counld not load image at'+url))
}
image.src = url
document.body.appendChild(image)
})
}
let urlimg = 'https://static.likepoems.com/cdn/sakurairo/logo.jpg'
loadImageAsync(urlimg).then(function(image){
console.log(`Image loaded:${image.src}`);
},function(error){
console.log(error);
})

3.2 使用Promise封装ajax

function getData(url) {
let promise = new Promise(function (resolve, reject) {
// 异步操作 - 做数据请求
let ajax = new XMLHttpRequest();
ajax.open('get', url);
ajax.send();
ajax.onreadystatechange = function () {
if (ajax.readyState === 4) {
if (ajax.status === 200) {
// 成功
resolve(ajax.responseText);
} else {
// 失败
reject(ajax);
}
}
}
});
return promise;
}
// 使用

getData('./1.txt').then(function (d) {

console.log(d);

console.log('成功');

}, function (err) {

console.log(err);

console.log('失败');

});

运行结果:

3.3 then方法与链式操作

举个例子:

2.txt

{
"name":"李明",
"sex":"男",
"url":"./2.txt"
}
getData('./2.txt').then(function (d) {
console.log('步骤1', JSON.parse(d).url);
return getData(JSON.parse(d).url);
}).then(function (d) {
console.log('步骤2', JSON.parse(d).url);
return getData(JSON.parse(d).url);
}).then(function (d) {
console.log('步骤3', JSON.parse(d).url);
return getData(JSON.parse(d).url);
})

输出结果:
步骤1 ./2.txt
步骤2 ./2.txt
步骤3 ./2.txt

Promise实例的then( )可以一直调用下去。

3.4 出现错误的处理

getData('./2.txt').then(function (d) {
console.log('步骤1', JSON.parse(d).url);
}).then(function (d) {
console.log('步骤2', JSON.parse(d).url);
resolve();
}).then(function (d) {
throw new Error("Error");
console.log("then");
}).catch(function (err) {
console.log("catch error:" + err.message);
});

输出结果:
步骤1 ./2.txt
catch error:Unexpected token u in JSON at position 0

总结:
若遇到异常抛出,会顺着promise链寻找下一个onRejected失败回调函数或者由catch指定的回调函数。我们一般使用catch来终止promise链,避免链条中的rejection抛出错误到全局

3.5 Promise.all()使用方法

举个例子:

let p1 = new Promise((res, rej) => {
setTimeout(() => {
res("p1")
}, 1000)
})
let p2 = new Promise((res, rej) => {
setTimeout(() => {
res("p2")
}, 2000)
})
let p3 = new Promise((res, rej) => {
setTimeout(() => {
res("p3")
}, 3000)
})
// 接收多个promise对象并返回一个promise对象
Promise.all([p1, p2, p3]).then((r) => {
console.log(r);
}).catch((err) => {
console.log(err.message);
})

输出结果:
[ 'p1', 'p2', 'p3' ]

总结: Promise.all( )实参是所有Promise实例的字面量组成的数组,执行完毕的结果是所有输出结果的所组成的数组。

4、拓展:async/await

4.1 async的使用

async函数使得异步操作变得更加方便

// async函数会返回一个Promise对象
async function hello() {
return "helloworld"
}
console.log(hello());
hello().then((r)=>{
console.log(r);
})

输出结果:
Promise { 'helloworld' }
helloworld

4.2 await的使用

await可以让代码暂停下来等待异步任务完成,await关键字只能放在async标识的异步函数里面才能够生效。
举个例子:

function getNumber() {
return new Promise((res, rej) => {
setTimeout(() => {
res(12)
}, 2000)
})
}
async function test() {
let r = await getNumber().then(v => v)
r++
return r
}
test().then(v => console.log(v))

输出结果:
13

function getNumber() {
return new Promise((res, rej) => {
setTimeout(() => {
res(12)
}, 2000)
})
}
let r = await getNumber().then(v => v)
console.log(r);

输出结果:
SyntaxError: await is only valid in async function(语法错误)

ES6 学习笔记(十三)promise的简单使用的更多相关文章

  1. ES6学习笔记之Promise

    入职百度EFE团队实习已经三周了,实习中接触到了生产环境的技术和开发流程,大开眼界,和自己在学校接小作坊式项目是很不一样的体验.其中一个很大的感触是,ES6早已不是“选修”的尝鲜技术,而是已经全面普及 ...

  2. java之jvm学习笔记十三(jvm基本结构)

    java之jvm学习笔记十三(jvm基本结构) 这一节,主要来学习jvm的基本结构,也就是概述.说是概述,内容很多,而且概念量也很大,不过关于概念方面,你不用担心,我完全有信心,让概念在你的脑子里变成 ...

  3. es6学习笔记-class之一概念

    前段时间复习了面向对象这一部分,其中提到在es6之前,Javasript是没有类的概念的,只从es6之后出现了类的概念和继承.于是乎,花时间学习一下class. 简介 JavaScript 语言中,生 ...

  4. ES6学习笔记<五> Module的操作——import、export、as

    import export 这两个家伙对应的就是es6自己的 module功能. 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小 ...

  5. ES6学习笔记<二>arrow functions 箭头函数、template string、destructuring

    接着上一篇的说. arrow functions 箭头函数 => 更便捷的函数声明 document.getElementById("click_1").onclick = ...

  6. ES6学习笔记<一> let const class extends super

    学习参考地址1  学习参考地址2 ECMAScript 6(以下简称ES6)是JavaScript语言的下一代标准.因为当前版本的ES6是在2015年发布的,所以又称ECMAScript 2015:也 ...

  7. Go语言学习笔记十三: Map集合

    Go语言学习笔记十三: Map集合 Map在每种语言中基本都有,Java中是属于集合类Map,其包括HashMap, TreeMap等.而Python语言直接就属于一种类型,写法上比Java还简单. ...

  8. ES6学习笔记之块级作用域

    ES6学习笔记:块级作用域 作用域分类 全局作用域 局部作用域 块级作用域 全局作用域示例 var i=2; for (var i = 0; i < 10; i++) { } console.l ...

  9. JS&ES6学习笔记(持续更新)

    ES6学习笔记(2019.7.29) 目录 ES6学习笔记(2019.7.29) let和const let let 基本用法 let 不存在变量提升 暂时性死区 不允许重复声明 块级作用域 级作用域 ...

  10. python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息,抓取政府网新闻内容

    python3.4学习笔记(十三) 网络爬虫实例代码,使用pyspider抓取多牛投资吧里面的文章信息PySpider:一个国人编写的强大的网络爬虫系统并带有强大的WebUI,采用Python语言编写 ...

随机推荐

  1. UIView Animation 动画学习总结

    目录 一.前言 二.UIView Animation 2.1 简单动画 2.2 关键帧动画 2.3 View 的转换 三.CALayer Animation 3.1 基本动画(CABasicAnima ...

  2. iOS 组件化及二进制化的探索

    组件化的优缺点 组件化的拆分 组件与组件之间如何进行通讯(路由) 从Cocopods拉取代码的过程 远程索引库里很多的.spec文件,该文件记录了很多内容,如用户名,框架名称,描述,框架的地址 Pod ...

  3. 第七十二篇:Vue组件的props

    好家伙, 1.组件的props props是组件的自定义属性,在封装通用组件的时候,合理的使用props可以极大的提高组件的复用性 来假设一下,如果我们需要两个组件分别显示不同的值 目录结构如下: H ...

  4. 微信小程序语音提示

    一. 老规矩, 先上demo图:  然后通过 wx.createInnerAudioContext  创建内部 audio 上下文 InnerAudioContext 对象 就能播放 filename ...

  5. 003-simonyanVeryDeepConvolutional2015(VGG)

    Very Deep Convolutional Networks for Large-Scale Image Recognition #paper 1. paper-info 1.1 Metadata ...

  6. v-contextmenujs 右键菜单点击

    忙碌了一晚上的"枫师傅"用上了新插件v-contextmenujs,这个插件就按照他的文档来就行 我的使用: <!-- 这里是demo.vue,之所以选择html是为了代码高 ...

  7. Kafka为什么性能这么快?4大核心原因详解

    Kafka的性能快这是大厂Java面试经常问的一个话题,下面我就重点讲解Kafka为什么性能这么快的4大核心原因@mikechen 1.页缓存技术 Kafka 是基于操作系统 的页缓存(page ca ...

  8. MySQL8更改数据存储目录

  9. Git pull 强制拉取并覆盖本地代码

    git fetch --all git reset --hard origin/master git pull

  10. Docker/K8s 解决容器内时区不一致方案

    转载自:https://cloud.tencent.com/developer/article/1433215 1.背景介绍 我们知道,使用 docker 容器启动服务后,如果使用默认 Centos ...