这样理解 promise

16次阅读

共计 4201 个字符,预计需要花费 11 分钟才能阅读完成。

promise 是什么
官网解释 promise 表示一个异步操作的最终结果。
翻译 == 可以将 promise 理解为一个状态机 ==,它存在三种不同的状态,并在某一时刻只能有一种状态

pending 表示还在执行
resolved 执行成功
rejected 执行失败

一个 promise 是对一个异步操作的封装,异步操作有等待完成、成功和失败三种可能的结果,对应了 promise 的三种状态。
promise 的状态只能有 pending 转换位 resolved 或者 pending 转换为 rejected,一旦状态转化完成就无法再改变。
假设我们用 promise 封了一个异步操作,那么当它被创建的时候就处于 pending 状态,当异步操作成功完成时,我们将状态转换为 resolved,如果执行中出现错误,将状态转换为 rejected。
var promise=new Promise(function(resolve,reject){
// code
if(){
/* 异步操作成功 */
resolve(value)
}else{
reject(error)
}
})
使用 then 方法获取结果
var fs=require(‘fs’)
function readFile_promise(path){
return new Promise(function(resolve,reject){
fs.readFile(path, ‘utf-8’,function(err,data){
if(data){
resolve(data)
}else{
reject(err)
}
})
})
}

var result=readFile_promise(‘./1.txt’)
result.then(function(value){
//success
console.log(‘success’, value)
},function(error){
//failure
console.log(‘failure’,error)
})
// 将一个异步函数封装成 promise,只要在回调函数中针对不同的返回结果调用 resolve 或者 reject 方法。

// resolve 函数会在异步操作成功完成时被调用,并将异步操作的返回值作为参数传递到外部。
// reject 是在异步操作出现异常时被调用,会将错误信息作为参数传递出去。
then 方法的返回值
then 方法总是返回一个新的 promise 对象,多次调用 then 方法,默认返回一个一个空的 promise 对象使用 return 来来返回。
var promise=readFile_promise(‘./foo.txt’)
promise.then(function(value){
//success
console.log(‘success’, value) // foo
return readFile_promise(‘./bar.txt’)
},function(error){
//failure
console.log(‘failure’,error)
}).then(function(value){
console.log(‘then’, value) // bar
})
promise 的执行
虽然我们是通过 then 方法来获取 promise 的结果,但是 promise 是当 then 方法调用之后才执行吗?
var promise=new Promise((resolve, reject)=>{
console.log(‘begin’)
resolve()
})

setTimeout(()=>{
promise.then(()=>{
console.log(‘end’)
})
},5000)
// 开始 begin 5s 后 end
// 运行顺序是,当 promise 从被创建的那一刻起就开始执行了,then 方法只是提供了访问 promise 状态的接口,与 promise 的执行无关。
promise 常用的 api

resolved
rejected
all
race 方法接收一个 promise 数组作为参数并返回一个新的 promise,数组中的 promise 会同时开始执行,race 返回的 promise 的状态有数组中率先执行完毕的 promise 的状态决定
catch 执行出错可以使用 throw 关键字抛出错误,并使用 catch 方法进行捕获

// 如果有多个 promise 需要执行,可以使用 promise.all()
// 方法统一声明,改方法可以将多个 promise 对象包装成一个 promise
// 该方法接收一个数组作为参数,数据的元素如果不是 promise 对象,则回先调用 resolve 方法转换。
// 如果中间有一个 promise 状态是 reject,那么转换后的 promise 也会变成 reject,并且将错误信息传给 catch 方法
var promises=[‘foo.txt’,’bar.txt’,’baz.txt’]
promises.map(function(path){
// console.log(path)
return readFile_promise(path)
})

Promise.all(promises).then(function(results){
console.log(results) // [‘foo.txt’, ‘bar.txt’, ‘baz.txt’] 顺序排列的
}).catch(function(err){
//
})
使用 promise 组织异步代码
// 例子;有三个文本文件需要顺序读取
var lists=[‘foo.txt’,’bar.txt’,’baz.txt’]
var count=0;
readFile_promise(‘foo.txt’).then(readCB).then(readCB).then(readCB);

function readCB(data){
console.log(data) // foo bar baz
if(++count>2){
return
}
return readFile_promise(lists[count])
}
async/await
await 关键字后面往往是一个 promise,如果不是就隐式调用 promise.resolve 来转换成一个 promise。await 等待后面的 promise 执行完成再进行下一步操作。
var asyncReadFile=async function(){
var result1=await readFile_promise(‘./foo.txt’)
console.log(result1.toString()) // foo
}
asyncReadFile()
async 返回值
async 函数总是会返回一个 promise 对象,如果 return 关键字后面不是一个 promise,那么默认调用 promise。resolve 方法进行转换。
async function asyncFunc(){
return ‘hello Node’
}
asyncFunc().then(function(data){
console.log(data) // hello Node
})
async 函数的执行过程

在 async 函数开始执行的时候回自动生成一个 promise 对象。
当方法体开始执行后,如果遇到 return 关键字或者 throw 关键字,执行会立刻退出,

如果遇到 await 关键字则回暂停执行 await 后面的异步操作结束后会恢复执行
执行完毕,返回一个 promise
async function asyncFunc(){
console.log(‘begin’)
return ‘hello Node’
}
asyncFunc().then(function(data){
console.log(data) // hello Node
console.log(‘end’)
})
// begin
// hello
// end
await
await 操作符的结果是由其后面 promise 对象的操作结果来决定的,如果后面 promise 对象变为 resolved,await 操作符发返回的值就是 resolve 的值;如果 promise 对象的状态变成 rejected,那么 await 也会抛出 reject 的值。
async function readFile(){
var result=await readFile_promise(‘./foo.txt’)
console.log(result) // foo
}
readFile()

// 等价于
readFile_promise(‘foo.txt’).then(function(data){
console.log(data) // foo
})
await 于并行
await 会等待后面的 promise 完成后再采取下一步动作,这意味着当多个 await 操作时,程序会便成完全的串行操作。
当异步操作之间不存在依赖关系时,可以使用 promise.all 来实现并行。
async function readFile(){
const [result1, result2]=await Promise.all([
readFile_promise(‘./foo.txt’),
readFile_promise(‘./bar.txt’)
])
console.log(result1, result2) // foo bar
}
readFile()

// 等价于
function readFile(){
return Promise.all([
readFile_promise(‘./foo.txt’),
readFile_promise(‘./baz.txt’)
]).then((result)=>{
console.log(result) // [‘foo’, ‘baz’]
})
}
readFile()
await 总结
await 关键字使用的一些关键点

await 关键字必须位于 async 函数内部
await 关键字后面需要是一个 promise 对象(不是的话就调用了 resolve 转换的)
await 关键字的返回结果就是在其后面 promise 执行的结果,可能是 resolved 或者 rejected 的值
不能在普通箭头函数中使用 await 关键字,需要在箭头函数前面加上 async 关键字。
await 用来串行地执行异步操作,想实现并行使用 promise.all

async 函数 的缺点
假设我们有很多层的方法调用,最底层的异步操作被封装成了 async 方法,那么该函数的所有上层方法可能都要变成 async 方法。

正文完
 0