相关学习网站。本期简单介绍Promise,
如果大家喜欢下次将会和大家一起学习Promise源码分析
目录
异步编程
在js执行过程中可以随时进行其他任务而不必等待某个任务完成
需要异步编程的类型:
定时器
fs文件操作
ajax
数据库操作
解决方法:
-
回调函数
-
定时器
-
fs文件操作
-
ajax
-
数据库操作
-
-
promise
优点:
-
指定回调函数方式更灵活
-
支持链式调用,可以解决回调地狱问题
回调地狱问题:回调函数里嵌套多层异步编程
-
Promise
Promise是JavaScript中用于处理异步操作的一种机制
异步编程实现
-
定时器
fun(){ //创建promise对象 const p=new Promise((resolve,reject)=>{ //定时器模拟把响应发送到服务器再返回时间 setTimeout( ()=>{ //生成1~100间随机数 let a=Math.ceil(Math.random()*100) if(a<30){resolve(a)} //对象成功时调resolve函数,并且把对象状态设置为 成功 else{reject(a)} //对象成功时调reject函数,并且把对象状态设置为 失败 }, 1000)//延时1秒 }) //调用then( 对象成功时回调函数 , 对象失败时回调函数 ) p.then( (value)=>{alert("真tm牛x,这都叫你给中了!奖励奔驰大G一辆!!!"+a)}, (reason)=>{alert("没中,哈哈..."+a)}) }
-
创建promise对象
new Promise( (resolve,reject)=>{...} )
-
resolve(解决):对象成功时调resolve函数,并且把对象状态设置为 成功
-
reject(拒绝):对象不成功时调reject函数,并且把对象状态设置为 失败
-
-
then方法,设置成功/失败函数
p.then( (value)=>{成功}, (reason)=>{失败})
-
-
fs文件操作
//Node.js中引入核心模块fs,用于文件操作 const fs=require('fs') //创建promise对象 let p=new Promise((resolve,reject)=>{ //fs.readFile('目标文件位置',(err,data)=>{...}) fs.readFile('../resource/txt.txt', (err,data)=>{ //如果有错,调reject(err) if(err){reject(err)} //成功调resolve(data) resolve(data) }) }) //调用then() p.then( (value)=>{console.log(value.toString())}, (reason)=>{console.log(reason)} )
执行方法是在集成终端打开文件夹,输入 node fs_demo.js
fsNode.js中核心模块.用于文件操作
-
ajax
$("input").click(()=>{ //创建promise对象 const p=new Promise((resolve,reject)=>{ //$.get( 发送请求的url ,成功后的回调函数 ) $.get( 'https://api.apiopen.top/getJoke', (response)=>{resolve(response)} ) .fail((status)=>{ reject(status) }); }) //调用then() p.then( (value)=>{console.log(value)}, (reason)=>{console.log(reason)} ) })
属性
PromiseState
是promise内置的一种属性,表示promise状态.
PromiseState有以下三种取值:
-
待定(pending):初始状态,既没有被兑现,也没有被拒绝。
-
已兑现(resolved/fulfilled):意味着操作成功完成。
-
已拒绝(rejected):意味着操作失败。
如果一个 Promise 已经被兑现或拒绝,即不再处于待定状态,那么则称之为已敲定(settled)
-
状态改变
-
待定 --> 已兑现
-
待定 --> 已拒绝
-
只能有这两种情况
-
promise状态只能改变一次
-
-
改变Promise状态方法
-
resolve('PromiseResul结果值') pending-->fulfilled/resolved
-
reject('PromiseResul结果值') pending-->rejected
-
throw 'PromiseResul结果值' pending-->rejected
-
PromiseResult
是promise内置属性,保存异步任务对象promise成功/失败后返回结果
可以通过resolve()或reject()对PromiseResult赋值
基本流程
流程图展示了 Promise 状态在 pending、fulfilled 和 rejected 之间如何通过 then() 和 catch() 处理程序进行转换。
一个待定的 Promise 可以变成已兑现或已拒绝的状态。
如果 Promise 已经兑现,则会执行“on fulfillment”处理程序(即 then() 方法的第一个参数 ),并继续执行进一步的异步操作。
如果 Promise 被拒绝,则会执行错误处理程序,可以将其作为then() 方法的第二个参数或 catch() 方法的唯一参数来传递。
Promise ajax请求
-
自己封装promis sendAJAX(url): 向url发送get ajax请求
-
在项目整体包下初始化npm项目: 项目名>
npm init --yes
-
在项目的code下安装Express框架: 项目名/code>
npm i express
启动一个 Node.js 服务器: 项目名/code>
node server.js
server.js内容参考ajax笔记
-
//自己封装: promise sendAJAX(url):向url发送get ajax请求
function sendAJAX(url){
return new Promise((resolve,reject)=>{
$.get( url, (Response)=>{resolve(Response)})
.fail(()=>{reject(state)})
})
}
//Test
sendAJAX('http://127.0.0.1:8000/jquery_server').then(
(value)=>{console.log(value)},
(reason)=>{console.warn(reason)}
)
Promise使用
构造函数
new Promise(executor)
-
executor函数: 执行器,会在promise内部同步调用(立即执行),异步操作在执行器中执行
(resolve,reject)=>{...}
-
resolve函数: 内部定义的,成功时调用(value)=>{...}
-
reject函数: 内部定义的,失败时调用(reason)=>{...}
-
then
Promise Promise.prototype.then(onResolved,onRejected)
Promise.prototype可以自定义或修改内置的 Promise 方法的行为
then为Promise指定成功/失败回调,
返回一受回调函数影响的新Promise (可链式调用 )
let result=p.then((value)=>{回调函数})
-
回调函数抛出异常: ```throw "异常"
返回Promise 状态:失败, 结果:"异常"
-
回调函数返回结果为非Promise对象: ```return 666
返回Promise 状态:成功, 结果:666
-
回调函数返回结果为Promise对象: ...
返回Promise 状态和结果都和回调函数return的Promise对象一样
-
回调函数无返回值
返回的Promise 状态:成功, 结果:undefined
若指定多个回调,则当Promise对象状态改变时都会执行
-
onResolved回调: 成功时回调 (value)=>{...} ,返回新Promise对象
-
onRejected回调: 失败时调用(reason)=>{...}
catch
Promise.prototype.catch(onRejected)
是实例的方法
-
onRejected回调: 失败时调用(reason)=>{...}
resolve
Promise Promise.resolve(value)
不是实例的方法,是Promise对象的方法
不用构造函数,Promise.resolve(...)也可以创建一个Promise对象
-
value:传入PromiseResult值, 可以是Promise类型也可以是非Promise类型
//当传入参数为非Promise类型对象时,返回PromiseState为成功的Promise对象
let p1=Promise.resolve(666)
console.log(p1)
//当传入参数为Promise类型对象时,返回PromiseState取决于参数Promise
let p2=Promise.resolve(new Promise((resolve,reject)=>{
/*当内部Promise回调成功,p2PromiseState也成功
resolve('ok')*/
//当内部Promise回调失败,p2PromiseState也失败
reject('error')
}))
p2.catch((reason)=>{
console.log(reason)
})
reject
Promise Promise.reject(reason)
Promise对象的方法
返回失败的Promise对象
-
reason:传入PromiseResult值
//Promise Promise.reject(传入PromiseResult值)
let p=Promise.reject(666)
//失败后处理
p.catch((reason)=>{
console.log(reason)
})
console.log(p)
all
Promise Promise.all(Promise[])
传入Promise数组,返回一个新Promise对象,其PromiseState取决于Promise数组
-
当Promise数组PromiseState全成功时,
新Promise对象PromiseState成功
新Promise对象PromiseResult为Promise数组的PromiseResult组成的数组
-
否则,新Promise对象PromiseState失败
新Promise对象PromiseResult为 Promise数组 中第一个失败Promise的PromiseResult
Promise对象方法
//当Promise数组全成功
let p1=Promise.resolve('111')
let p2=Promise.resolve('222')
let p3=Promise.resolve('333')
let p=Promise.all([p1,p2,p3])
console.log(p)
//当Promise数组中存在失败的
let p1=Promise.resolve('111')
//p2,p3都失败, 但最终p的PromiseResult为第一个失败的PromiseResult
let p2=Promise.reject('222')
let p3=Promise.reject('333')
let p=Promise.all([p1,p2,p3])
console.log(p)
race
Promise Promise.race(Promise[])
传入Promise数组,返回一个新Promise对象,
新对象=第一个改变状态的Promise
Promise对象的方法
let p1=new Promise((resolve,reject)=>{
setTimeout(()=>{resolve('111')},1000) //p1等1秒后状态改为成功
})
let p2=Promise.resolve('222') //p2是第一个改变状态的
let p3=Promise.reject('333')
let p=Promise.race([p1,p2,p3]) //返回结果=p2
console.log(p)
链式调用
链式调用:回调方法then返回Promise对象又可以对其使用.then(...)
//p 状态:成功, 结果:'ok'
let p=new Promise((resolve,reject)=>{
setTimeout(()=>{resolve('ok')},1000) //p等1秒后状态改为成功
})
//返回Promise 状态:成功, 结果:undefined(因为回调函数没return)
p.then((value)=>{console.log(value)}) //value(结果):undefined
.then((value)=>{console.log(value)})
为了更快的执行,最好将所有同步操作都放在一个处理程序中,否则如果将它们拆分为多个处理程序,执行所有处理程序将需要几个时钟周期。
中断链条
链中每个已兑现的 Promise 的返回值会传递给下一个 .then(),
而已拒绝的 Promise 会把失败原因传递给链中下一个拒绝处理函数。
当且仅当Promise状态为 待定(pending)时才会中断链条
因为待定的Promise状态未改变,不能调用.then()
let p=new Promise((resolve,reject)=>{
setTimeout(()=>{resolve('ok')},1000) //p等1秒后状态改为成功
})
p.then((value)=>{console.log('111')})
//返回pending状态的Promise无法调用.then()
.then((value)=>{console.log('222');return new Promise(()=>{})})
.then((value)=>{console.log('333')})
.catch((reason)=>{console.warn(reason)})
异常穿透
穿透处理:当有多个then链式调用时,在最后加上.catch((reason)=>{异常处理})
无论是哪一环失败了,都会执行'异常处理'
let p=new Promise((resolve,reject)=>{
setTimeout(()=>{resolve('ok')},1000) //p等1秒后状态改为成功
})
p.then((value)=>{console.log('111')})
.then((value)=>{console.log('222');throw '出错了'})
.then((value)=>{console.log('333')})
.catch((reason)=>{console.warn(reason)})
Node.js相关核心模块
fs
用于文件操作,如读取、写入、删除、重命名文件等
使用fs模块需要先引入该模块 ( const fs=require('fs') )
然后通过调用其提供的API函数来完成相关操作
-
fs.readFile() 读取文件内容
-
fs.writeFile() 写入文件内容
-
fs.unlink() 删除文件
-
fs.rename() 重命名文件
util
在 Node.js 中有一个内置的 "util" 模块
用于提供一系列实用函数,如格式化字符串、处理对象继承等
util.promisify
util.promisify (js.readFile)
回调-->promise
用于将基于回调的异步函数转换为返回 Promise 的函数
fs.readFile(path,(err,data)=>{...}) --> util.promisify(fs.readFile)
-
自己封装函数:
给一个目标文件地址返回一个promise对象
//封装一个函数:promise My_ReadFile('目标文件地址')
function My_ReadFile(path){
return new Promise((resolve,reject)=>{
//引入fs.读文件
require('fs').readFile(path,(err,data)=>{
//失败
if(err){reject(err)}
//成功
resolve(data)
})
})
}
//Test
My_ReadFile('./resource/txt.txt')
.then(
(value)=>{console.log(value.toString())},
(reason)=>{console.warn(reason)}
)
-
util.promisify
//util内置函数promisify(js.readFile)
//引入util
const util=require('util')
let ReadFile=util.promisify(require('fs').readFile)
//Test
ReadFile('./resource/txt.txt').then(
(value)=>{console.log(value.toString())},
(reason)=>{console.warn(reason)}
)
将fs.readFile()函数转换为返回Promise的形式