JavaScript. promise 非同步观念

promise 经常与 Ajax 共同谈论,但这篇文章会以 promise 为主;promise 是一个语法,专门用来处理与优化非同步行为,我们知道 JavaScript 属于同步程式语言,因此它一次只会做一件事,遇到非同步事件的时候,就会等到所有的原始码运行完,才会执行非同步的事件。

这边强调的是执行的顺序,只要是非同步一定都会放在最后才执行,即使 setTimeout() 的时间设定是 0,也同样放到最后。

function getData() {setTimeout(() => {    console.log('... 已取得远端资料');  }, 0);}const component = {  init() {    console.log(1);     getData(); // 非同步    console.log(2);   }}component.init(); 

结果:

12... 已取得远端资料

Promise 结构

promise 是一个建构式函式,函式也属于物件,我们可以附加其他属性方法,promise 可以直接使用 allraceresolvereject 等方法,下面这几种方法皆可以直接 console 查看:

promise.allpromise.racepromise.resolvepromise.reject

promise 建构函式 new 出的新物件,也可以在 prototype 内使用其中的原型方法,在这里面也包含了 thencatchfinally,如果要呼叫他们,则必须在新产生的物件下才能呼叫。

透过 new Promise() 的方法建立 a 物件,a 就能使用 promise 的原型方法,範例如下:

const a = new Promise();a.then(); // promise 回传正确a.catch(); // promise 回传失败a.finally(); // 非同步执行完毕(无论是否正确完成,非同步都会在最后被执行完毕)

在 promise 事件里,我们必须给予参数让它回传结果,通常会给予 resolvereject 这两个参数,他们分别代表回传成功及失败,并且仅能回传其中一个。另外,这两个参数也可以自己定义名称,但大部分的开发者会习惯用本来的名字。

new Promise(function(resolve, reject){resolve(); // 正确完成的回传reject(); // 失败的回传});

Promise 状态

promise 的执行过程中也包括下面这几种状态:

pending / 事件正在运行中,但还没有获得结果。resolved / 事件已经正确执行完毕,并回传 resolve 的结果,resolve 会回传成功。rejected / 事件已经执行完毕,并回传 reject 的结果,reject 会回传错误。

以下範例可以大致说明 promise 的运行过程:

const promiseSetTimeout = (status) => {  return new Promise((resolve, reject) => {// setTimeout 在这里就是一个非同步的状态    setTimeout(() => {      if (status) {        resolve('promiseSetTimeout 成功')      } else {        reject('promiseSetTimeout 失败')      }    }, 0);  })}

pending 之后会有两个状态 Fulfilled 和 Rejected,Fulfilled ( 成功 ) 会使用 resolve 回传结果,并用 then 来做接收,Rejected ( 失败 ) 会使用 reject 回传结果,并用 thencatch 来做接收,但如果前面有 then,则会跳过,直接用 catch 做接收。

另外,我们要如何确定 promise 是否完成?这时候可以依据 resolvereject 是否有被调用,如果没有被调用, promise 的结果会停留在 pending

function promise() {  return new Promise((resolve, reject) => {});}console.dir(promise()); // [[PromiseState]]: "pending"

执行上面程式码,我们可以看到在 promise 函式中有下面两种属性:

[[PromiseStatus]]:"pending" 目前的进度状态。[[PromiseValue]]:undefinedresolvereject 回传的值。
promise[[Prototype]]: Promise[[PromiseState]]: "pending"[[PromiseResult]]: undefined

建立 Promise

函式陈述式建立以后,透过 return new Promise 回传并建立一个 promise 物件,在内部执行 promise 函式并加入参数 resolvereject,这个阶段就是常见的 promise 结构,接着等待 resolvereject 回传结果就可以完成整个程序。

这个範例会随机调用 resolve 和 reject:

function promise() {  return new Promise((resolve, reject) => {    // 随机取得 0 or 1    const num = Math.random() > 0.5 ? 1 : 0;    // 1 则执行 resolve,否则执行 reject    if (num) {       resolve('成功');    }    reject('失败')  });}

第二个範例也可以看到函式最后的结果是回传 resolve,并且能够回传 resolved 的状态和值。

const promiseSetTimeout = (status) => {  return new Promise((resolve, reject) => {    setTimeout(() => {      if (status) {        resolve('promiseSetTimeout 成功')      } else {        reject('promiseSetTimeout 失败')      }    }, 0);  })}
promiseSetTimeout(true).then(function(res){console.log(res); // "promiseSetTimeout 成功" 回传成功})

结果:

Promise {<pending>}[[Prototype]]: Promise[[PromiseState]]: "fulfilled"[[PromiseResult]]: undefined

Promise 链接

promise 在 thencatch 都可以使用链接的方式不断的进行任务,这个範例的 promise 传入 0 会调用 reject,其他数值则是 resolve

function promise(num) {  return new Promise((resolve, reject) => {    num ? resolve(`${num}, 成功`) : reject('失败');  });}

如果我们希望 promise 可以接着进行下一个任务,可使用 return 进入下一个 then,这边的 return 也有一些特点:

不侷限于 promise 函式,任何表达式都可进行回传。promise 函式的 return 会遵循 thencatch 的运作。如果不是 promise 函式,再下一个 then 则可以取得结果。
promise(1)  .then(success => {    console.log(success);    return promise(2);  })  .then(success => {    console.log(success);    return promise(0); // 这个阶段会进入 catch  })  .then(success => {   // 由于上一个阶段结果是 reject,所以此段不执行    console.log(success);    return promise(3);  })  .catch(fail => {    console.log(fail);  })

Promise 方法

上面有提到几个 promise 的方法,这边回头来讨论一下,在 promise物件下,展开可以看到这些方法。

promise.all

以阵列的形式传入数个 promise 函式,并且以同样的顺序回传,且为阵列结果。

Promise.all([promise(1), promise(2), promise(3, 3000)])  .then(res => {    console.log(res);  });
promise.race

以阵列的形式传入数个 promise 函式,但在全部执行完毕以后只会回传单一个结果,并且回传的是第一个执行完毕的阵列,以下列範例来说,回传的是 promise(1)

Promise.race([promise(1), promise(2), promise(3, 3000)]).then(res => {  console.log(res);});
promise.resolve 和 promise.reject

这两个方法其实就是回传 promise 运行完毕的状态;resolve 回传操作成功,reject 回传操作失败,并且通常只会回传其中一个结果。

var result = Promise.resolve('result');result.then(res => {  console.log('resolved', res); // 成功部分可以正确接收结果}, res => {  console.log('rejected', res); // 失败部分不会取得结果});

此篇文章感谢卡斯伯老师详细的文章讲解,为了学习和记忆我也尽量用自己的话整理出来,如果有理解错误的地方也请看过的大神们不吝啬告知,或也可以看看卡斯伯老师详细的 promise 全介绍。

参考资料:

JavaScript Promise 全介绍


关于作者: 网站小编

码农网专注IT技术教程资源分享平台,学习资源下载网站,58码农网包含计算机技术、网站程序源码下载、编程技术论坛、互联网资源下载等产品服务,提供原创、优质、完整内容的专业码农交流分享平台。

热门文章