一.什么是Promise:

一.什么是Promise:

预备知识

1.1 实例对象与函数对象

实例对象:new 函数产生的对象,称为实例对象,简称为对象

函数对象:将函数作为对象使用时,称为函数对象

function Fn() { // Fn只能称为函数

}

const fn = new Fn() // Fn只有new过的才可以称为构造函数

//fn称为实例对象

console.log(Fn.prototype)// Fn作为对象使用时,才可以称为函数对象

Fn.bind({}) //Fn作为函数对象使用

$('#test') // $作为函数使用

$.get('/test') // $作为函数对象使用

()左边是函数,点左边是对象(函数对象、实例对象)

1.2 两种类型的回调函数

1. 同步回调

立即执行,完全执行完了才结束,不会放入回调队列中

数组遍历相关的回调 / Promise的executor函数

const arr = [1, 3, 5];

arr.forEach(item => { // 遍历回调,同步回调,不会放入队列,一上来就要执行

console.log(item);

})

console.log('forEach()之后')

2. 异步回调

不会立即执行,会放入回调队列中将来执行

定时器回调 / ajax回调 / Promise成功或失败的回调

// 定时器回调

setTimeout(() => { // 异步回调,会放入队列中将来执行

console.log('timeout callback()')

}, 0)

console.log('setTimeout()之后')

// Promise 成功或失败的回调

new Promise((resolve, reject) => {

resolve(1)

}).then(

value => {console.log('value', value)},

reason => {console.log('reason', reason)}

)

console.log('----')

// ----

// value 1

js 引擎先把初始化的同步代码都执行完成后,才执行回调队列中的代码

1.3 JS中的异常error处理

1. 错误的类型

Error:所有错误的父类型

ReferenceError:引用的变量不存在

console.log(a) // ReferenceError:a is not defined

TypeError:数据类型不正确

let b

console.log(b.xxx)

// TypeError:Cannot read property 'xxx' of undefined

let c = {}

c.xxx()

// TypeError:c.xxx is not a function

RangeError:数据值不在其所允许的范围内

function fn() {

fn()

}

fn()

// RangeError:Maximum call stack size exceeded

SyntaxError:语法错误

const c = """"

// SyntaxError:Unexpected string

2. 错误处理(捕获与抛出)

抛出错误:throw error

function something() {

if (Date.now()%2===1) {

console.log('当前时间为奇数,可以执行任务')

} else { //如果时间为偶数抛出异常,由调用来处理

throw new Error('当前时间为偶数,无法执行任务')

}

}

捕获错误:try ... catch

// 捕获处理异常

try {

something()

} catch (error) {

alert(error.message)

}

错误对象

-massage 属性:错误相关信息

-stack 属性:函数调用栈记录信息

try {

let d

console.log(d.xxx)

} catch (error) {

console.log(error.message)

console.log(error.stack)

}

console.log('出错之后')

// Cannot read property 'xxx' of undefined

// TypeError:Cannot read property 'xxx' of undefined

// 出错之后

因为错误被捕获处理了,后面的代码才能运行下去,打印出‘出错之后’

一.什么是Promise:

Promise 是在 js 中进行异步编程的新解决方案。(以前旧的方案是单纯使用回调函数)

从语法来说,promise是一个构造函数。

从功能来说,promise对象用来封装一个异步操作,并且可以获得成功或失败的返回值。

JS中的常见的异步操作:定时器,AJAX中一般也是异步操作(也可以同步),回调函数可以理解为异步(不是严谨的异步操作)…等。

剩下的都是同步处理

二.为啥使用Promise:

promise使用回调函数更灵活。旧的回调函数必须在启动异步任务前指定。

promise:启动异步任务 => 返回promise对象 => 给promise对象绑定回调函数(甚至能在异步任务结束后指定多个)

promise支持链式调用,可以解决回调地狱问题。(回调地狱就是多层回调函数嵌套使用,就是套娃,这样就不利于阅读和异常处理。)

三. promise初体验:

效果:点击一个按钮,有30%概率显示中奖。

实现: 点击按钮后得到一个1到100间的随机数,小于等于30输出中奖,否则输出没中。期间用定时器模拟异步操作,在定时器里执行判断。

(1)基础的写法:

(2)promise写法,在promise里封装一个异步操作。

promise封装:

// 点击事件

btn.addEventListener('click',function(){

const p = new Promise((resolve,reject) => {

//创建对象

const xhr = new XMLHttpRequest();

//初始化

xhr.open('GET', "http://poetry.apiopen.top/sentences");

//发送

xhr.send();

//处理响应结果

xhr.onreadystatechange = function () {

if (xhr.readyState === 4) {

if (xhr.status >= 200 && xhr.status < 300) {

//输出响应体

resolve(xhr.response);

} else {

//输出响应状态码

reject(xhr.status);

}

}

}

})

p.then(value=>{

console.log(value);

},reason=>{

//控制台输出警告信息

console.warn(reason);

})

})

若把接口写错:

五:Promise封装ajax请求:

跟上一步差不多。就是把其封装在一个sendAJAX()的自定义函数里。

function sendAJAX(url) {

return new Promise((resolve, reject) => {

//创建对象

const xhr = new XMLHttpRequest();

xhr.responseType = 'json';

//初始化

xhr.open('GET', url);

//发送

xhr.send();

//处理响应结果

xhr.onreadystatechange = function () {

if (xhr.readyState === 4) {

if (xhr.status >= 200 && xhr.status < 300) {

//输出响应体

resolve(xhr.response);

} else {

//输出响应状态码

reject(xhr.status);

}

}

}

});

}

sendAJAX("http://poetry.apiopen.top/sentences")

.then(value=>{

console.log(value);

},reason=>{

//控制台输出警告信息

console.warn(reason);

})

六:promise的状态改变:

promise状态表示实例对象的一个属性

【PromiseState】。包括以下值:

(1)pending 未决定的

(2)resolved 或 fullfilled 成功

(3)rejected 失败

Promise对象的值表示实例对象的另一个属性

【PromiseResult】。保存着对象【成功/失败】的结果。而其状态改变只有以下两种可能:

(1)pending 变为resolved

(2)pending 变为 rejected

注:一个promise对象只能改变一次,无论成功或失败都会有一个结果数据,成功的称为 value , 失败的称为 reason 。

七:Promise基本流程图:

八:Promise的API 使用:

Promise 的构造函数:Promise(executor){}

(1)executor 函数:执行器 (resolve,reject)=> {}。

(2)resolve 函数:内部定义成功时调用函数 value => {} 。

(3)reject 函数:内部定义失败时调用函数 reason => {} 。

注意:Promise内部会立同步即调用executor,异步操作在执行器里执行。

Promise.prototype.then 方法: (onResolved, onRejected)=> {}

(1) onResolved 函数:成功的回调函数 (value) => {}

(2) onRejected 函数:失败的回调函数 (reason) => {}

注:指定用于得到成功value的成功回调和用于得到失败reason的失败回调是返回一个新的promise对象。

Promise.prototype.catch万法: (onRejected) => {}

onRejected.函数: 失败的回调函数(reason)=> {}

注:只是失败的调用。then()的语法糖,相当于: then(undefined, onRejected)。

Promise.resolve 方法: (value)=> {}

value: 成功的数据或promise对象

注:如果传入的参数为非Promise类 型的对象,则返回的结果为成功promise对象,如果传入的参数为Promise 对象,则参数的结果决定了resolve 的结果。

Promise.reject 方法: (reason) => {}

reason: 失败的原因

注:无论传入啥只返回一个失败的promise对象。

Promise.all 方法: (promises)=> {}

promises: 包含n个promise的数组

注:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败。失败了返回那个失败值。

Promise.race 方法: (promises)=> {}

promises: 包含n个promise的数组

注:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态。

来一个例子:

let p1 = new Promise((resolve,reject)=>{

setTimeout(()=>{

resolve('yes');

},1000)

})

let p2 = Promise.resolve('success');

let p3 = Promise.resolve('come');

const result = Promise.race([p1,p2,p3]);

console.log(result);

九:使用Promise面临的关键问题:

1.如何改变 promise的状态?

(1) resolve(value): 如果当前是pending就会变为resolved。

(2) reject(reason): 如果当前是pending就会变为rejected。

(3)抛出异常 throw :如果当前是pending就会变为rejected。

let p1 = new Promise((resolve,reject)=>{

// resolve('success');

// reject('error');

// throw 'error';

})

2.一个 promise指定多个成功/失败回调函数,都会调用吗?

当promise改变为对应状态时都会调用。

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

resolve('success');

})

// 第一次回调

p.then(value=>{

console.log("yes");

})

// 第二次回调

p.then(value=>{

console.log("oh yes");

})

3.改变 promiseT状态和指定回调函数谁先谁后?

(1)都有可能, 正常情况下是先指定回调再改变状态,但也可以先改状态再指定回调

(2)如何先改状态再指定回调?

①在执行 器中直接调用resolve(/reject();

②延迟更 长时间才调用then();

(3)什么时候才能得到数据?

①如果先指定的回调, 那当状态发生改变时,回调函数就会调用,得到数据

②如果先改变的状态, 那当指定回调时,回调函数就会调用,得到数据

4. promise.then()返回的新promise的结果状态由什么决定?

(1)简单表达: then()指定的回调函数执行的结果决定。

(2)详细表达:

*如果抛出异常, 新promise变为rejected, reaon为抛出的异常。

*如果返回的是非prormise的任意值,新promise变为resolved, value为返回的值。

*如果返回的是另一个新promise,此promise的结果就会成为新promise的结果。

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

// resolve('success');

// reject('No');

// throw 'oh no';

});

let result = p.then(value => {

console.log(value);

}, reason => {

console.warn(reason);

});

console.log(result);

5. promise 如何串连多个操作任务?

(1) promise 的then()返回一个新的promise,可以开成then()的链式调用。

(2)通过then的链式调用串连多个同步/异步任务。

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

resolve("yes");

})

p.then(value => {

return new Promise((resolve,reject)=>{

resolve("oh yes~");

});

}).then(value => {

console.log(value);

})

输出结果:

oh yes~

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

resolve("yes");

})

p.then(value => {

return new Promise((resolve,reject)=>{

resolve("oh yes~");

});

}).then(value => {

console.log(value);

}).then(value => {

console.log(value);

})

输出结果:

oh yes~

undefined

6. promise 的异常穿透。

(1)当使用promise的then链式调用时,可以在最后指定失败的回调。

(2)前面任何操作出 了异常,都会传到最后失败的回调中处理。

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

setTimeout(()=>{

resolve("yes");

},1000);

})

p.then(value => {

throw 'oh No';

}).then(value => {

console.log("123");

}).then(value => {

console.log("456");

}).catch(reason=>{

console.warn(reason);

})

输出结果:

oh No

7.中断 promise链。

(1)当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数。

(2)办法:在回调函数中返回一个pendding状态的promise对象。

未中断:

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

setTimeout(()=>{

resolve("yes");

},1000);

})

p.then(value => {

console.log("789");

}).then(value => {

console.log("123");

}).then(value => {

console.log("456");

}).catch(reason=>{

console.warn(reason);

})

输出结果:

789

123

456

中断:

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

setTimeout(()=>{

resolve("yes");

},1000);

})

p.then(value => {

console.log("789");

return new Promise(()=>{});

}).then(value => {

console.log("123");

}).then(value => {

console.log("456");

}).catch(reason=>{

console.warn(reason);

})

输出结果:

789

十:Promise的自定义封装:(略)

十一:async函数:

1.函数的返回值为promise对象。

2.promise对象的结果由async函数执行的返回值决定。

3.其实跟 then()方法返回结果是一样一样的。

1.返回一个非Promise对象,返回值是resolve。

async function main(){

return '123';

}

let res = main();

console.log(res);

**2.如果返回是一个Promise对象,由返回结果决定:**

如:

async function main(){

return new Promise((resolve,reject)=>{

reject('NO');

});

}

let res = main();

console.log(res);

3.抛出异常也是失败

async function main(){

return new Promise((resolve,reject)=>{

reject('NO');

});

}

let res = main();

console.log(res);

十二.await表达式:

1.await右侧的表达式一般为promise对象,但也可以是其它的值。

2.如果表达式是promise对象,await返回的是promise成功的值。

3.如果表达式是其它值,直接将此值作为await的返回值。

注意:

1.await 必须写在async函数中,但async 函数中可以没有await 。

2.如果await的promise失败了,就会抛出异常,需要通过try…catch捕获处理。

1.右侧为promise对象

async function works(){

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

resolve('oh yes')

})

let res = await p;

console.log(res);

}

works();

结果:

oh yes

2.右侧为其它值:

async function works(){

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

resolve('oh yes')

})

// let res = await p;

let res = await 100;

console.log(res);

}

works();

结果:

100

3.如果promise是失败状态:

async function works(){

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

// resolve('oh yes')

reject('err');

})

try{

let res = await p;

}catch(e){

console.log(e);

}

}

works();

十三.async与await结合发生ajax请求:

效果: 点击按钮获取一句名言。

Document

相关文章