Promise

JS 的 Promise 看了好几次了,大概清楚概念,但是一直心里没底,也没写过代码,今天把这些心虚的部分一波带走。

Background

简单聊一下背景,众所周知 JavaScript 是以单线程的方式运行的。在某一时刻内只能执行特定的一个任务,并且会阻塞其它任务的执行。对于类似网络请求等耗时的任务,没必要等任务执行完后才继续后面的操作。在这些任务完成前,JavaScript 完全可以往下执行其他操作,当这些耗时的任务完成后则以回调的方式执行相应处理。这些就是 JavaScript 与生俱来的特性:异步与回调。

大概是这个样子:

networkQuery(queryUrl, function(err, data){
  if(err){
    console.log("error!")
  } else {
    // handle data
  }
})

当然这也带了一个坑,如果你需要执行多个耗时操作,并且他们之间存在执行结果数据之间的依赖,那你不得不把代码写成下面这样。回调地狱

networkQuery(queryUrl, function(err, data){
  if(err){
    console.log("First query error!")
  } else {
    queryFromBackEnd(data.someUrl, function(err, data){
      if(err){
        console.log("Second query error!")
      } else {
         queryFromOtherSystem(data.otherUrl, function(err, data){
           if(err){
             console.log("Error!")
           } else {
             console.log("Finally get data in Callback Hell")
           }
         })
      }
    })
  }
})

逻辑简单还好说,稍微复杂一点,第二天根本看不懂自己写了什么。

Promise

解决回调地狱的其中第一种方式就是使用 Promise。

Promise,如字面所说:承诺。

假装是代码:

我承诺(promise)今天要学会使用 Promise。然后(then)等到今天结束的时候,可能实现了承诺(resolve),不过也有可能遇到(catch)没有实现承诺的情况(reject)。

翻译一下:

let learnPromise = new Promise(function(resolve, reject){
  // Wait until the end of the day.
  // Check result: Do I understand how to use Promise?
  let understand = false;
  if(understand){
    resolve("Absolutely!")
  } else {
    reject("Not yet")
  }
})

learnPromise.then(function(messageFromResolve){
  console.log("Understood ? " + messageFromResolve)
}).catch(function(messageFromReject){
  console.log("Understood ? " + messageFromReject)
})

// OUTPUT
// Understood ? Not yet

第一行创建了一个 Promise 对象,创建的时候传入了一个函数,在函数内部进行耗时操作。

此外函数接收两个参数,这两个参数都是函数。分别是实现了承诺的后续操作函数 resolve,和没有实现承诺的后续操作函数 rejectresolvereject, 分别对应 代码的下半部分中 Promise 对象在调用 then() 时传入的函数,和调用 catch() 时传入的函数。

注意Promise 对象 learnPromise 的使用方式,then()catch(), Promise 让编写异步代码稍微看起来像在写同步代码一样。

Multiple Promises

回到最初的例子,回调地狱。如果使用 Promise,则每个 query 方法都不直接使用回调函数,而是返回一个 Promise 对象,调用的时候在每一个 resolve 函数的最后调用下一阶段的 query 函数返回对应的 Promise 对象(也就是在 then 中传入函数的最后返回一个 Promise 对象),就可以在 then 方法之后继续 调用 then

query()
.then( function(){ /* Return a Promise instance */})
.then( function(){ /* Return a Promise instance */})
.then( function(){ /* Return a Promise instance */})
.catch()

就像这样,我们把返回的结果 message 也作为参数传到了下一个 Promise,在最后一个 Promise 的 resolve 中打印。

let networkQuery = function(message){
  return new Promise((resolve, reject) => {
    let data = "First query result, based on " + message
    resolve(data);
  })
}

let queryFromBackEnd = function(message){
  return new Promise((resolve, reject) => {
    let data =  "Second query result, based on " + message
    resolve(data);
  })
}

let queryFromOtherSystem = function(message){
  return new Promise((resolve, reject) => {
    let data = "Third query result, based on " + message
    resolve(data);
  })
}
    
networkQuery("nothing").then(tempData => {
  return queryFromBackEnd(tempData)
}).then(data => {
  return queryFromOtherSystem(data)
}).then(finalData => {
  console.log(finalData)
})

// OUTPUT
// Third query result, based on Second query result, based on First query result, based on nothing

Other condition

当然有的时候我们或许并不关心执行的过程,只关心是否成功的执行完了所有任务,也可以这样使用

Promise.all([firstOperation(), secondOperation(), thirdOperation()]).then(() =>{
  console.log("All finished")
  // do something else
})

或者只要其中一个执行成功就可以了:

Promise.race([firstOperation(), secondOperation(), thirdOperation()]).then(() =>{
  console.log("One of them is finished")
  // do something else
})

最后,understand = true

好了,今天就到这里了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容