Promise实际操演

Promise

JavaScript 是属於同步的程序语言,因此一次仅能做一件事情,但遇到非同步的事件时,就会将非同步的事件移动到程序码的最後方,等到所有的原始码运行完以後才会执行非同步的事件。

以下列的程序码来说,在 console 中依序的会出现的顺序为:

  1. 开始
  2. 结束
  3. 非同步事件 <- 最後执行
console.log('开始');

setTimeout(() => {
  console.log('非同步事件');
}, 0);

console.log('结束');

虽然在上段的原始码中,setTimeout 所定义的时间为 0,但因为是属於非同步事件,因此还是会在其他原始码运行完以後才执行。

我们再axios文件中找一段实际范例参考,先定义一个data物件,中间段落使用 axios 尝试取得远端资料,後面的紧接的 console.log(data),实际测试看看console的结果是什麽?

你应该会觉得concole顺序依序为:

  1. "开始执行"
  2. '/user?ID=12345
  3. "测试有没有接收到资料"
let data = {}

console.log('开始执行');

const api = '/user?ID=12345'
axios.get(api).then(response => {
  data = response;
  console.log('测试有没有接收到资料');
});

console.log(data);

其实正确的 console 中依序的会出现的顺序是:

  1. "开始执行"
  2. [object Object] { ... }
  3. "测试有没有接收到资料"

你应该会想说为什麽console.log(data)会没有接收到资料呢?
因为上述的非同步行为,导致api还尚未接收到,因此才会出现[object]

实战演练Promise,以Vue为范例

一、数字题型:

const app = new Vue({
  el: '#app',
  created() {
    this.promise(100)
      .then(success => {
        console.log(success);
        return this.promise(1000);
      })
      .then(success => {
        console.log(success);
        return this.promise(0); // 这个阶段会进入 catch
      })
      .then(success => {   // 由於上一个阶段结果是 reject,所以此段不执行
        console.log(success);
        return this.promise('Hello');
      })
      .catch(error => {
        console.log(error);
      })
  },
  methods: {
    promise (num) {
      return new Promise((resolve, reject) => {
        num ? resolve('成功') : reject('失败');
      });
     }
   },
 })

因此console出来的结果为:

  1. 成功
  2. 成功
  3. 失败

二、JSON Data一般题型:
将题型一的值更改为JSON,分别为apiA以及apiB
可将此段程序码复制贴到开发者工具看有没有什麽不同的地方~

const app = new Vue({
  el: '#app',
    created () {
    const apiA = 'https://data.taipei/api/v1/dataset/80ab7634-dabd-4012-be8c-fb7da0101e9b?scope=resourceAquire'
    const apiB = 'https://data.taipei/api/v1/dataset/36847f3f-deff-4183-a5bb-800737591de5?scope=resourceAquire'
    this.demo(apiA).then(res => {
      console.log(res)
      return this.demo(apiB)
    }).then(res => {
      console.log(res)
    }).catch(err => {
      console.log(err)
    })
  },
  methods: {
    demo (api) {
      return new Promise((resolve, reject) => {
        axios.get(api).then((res) => {
          const data = res.data.result.results
          res.status === 200 ? resolve(data) : reject('error api')
        })
      })
    }
  }
})

三、进阶题型:
使用indexOf去寻找哪个api中有符合80ab7634的字串,有的话则会执行setTimeout延迟5秒!
然而,在这个范例中indexOf寻找到apiA有符合,但是js是由上到下去执行的,因此js会等待apiA回传回来後,接着马上跟着回传apiB,因此apiA与apiB都将延迟5秒回传

const app = new Vue({
  el: '#app',
  created() {
    const apiA = 'https://data.taipei/api/v1/dataset/80ab7634-dabd-4012-be8c-fb7da0101e9b?scope=resourceAquire'
    const apiB = 'https://data.taipei/api/v1/dataset/36847f3f-deff-4183-a5bb-800737591de5?scope=resourceAquire'
    this.demo(apiA).then(res => {
      console.log(res);
      return this.demo(apiB)
    }).then(res => {
      console.log(res);
    }).catch(err => {
      console.log(err);
    })
  },
  methods: {
    demo(api) {
      return new Promise((resolve, reject) => {
        axios.get(api).then((res) => {
          if (res.status === 200) {
            if (api.indexOf('80ab7634') > -1) {
              setTimeout(() => {
                resolve(res.data)
              }, 5000)
            } else {
              resolve(res.data)
            }
          } else {
            reject('error api')
          }
        })
      })
    },
  },
})

假如我们将indexOf的值变更为36847f3f,猜猜看会出现什麽有趣的事呢?
这时会发现,js先回传apiA,经过了5秒後才会回传apiB
因为js未搜寻到apiA有36847f3f的值,因此不会去执行setTimeOut

const app = new Vue({
  el: '#app',
  created() {
    const apiA = 'https://data.taipei/api/v1/dataset/80ab7634-dabd-4012-be8c-fb7da0101e9b?scope=resourceAquire'
    const apiB = 'https://data.taipei/api/v1/dataset/36847f3f-deff-4183-a5bb-800737591de5?scope=resourceAquire'
    this.demo(apiA).then(res => {
      console.log(res);
      return this.demo(apiB)
    }).then(res => {
      console.log(res);
    }).catch(err => {
      console.log(err);
    })
  },
  methods: {
    demo(api) {
      return new Promise((resolve, reject) => {
        axios.get(api).then((res) => {
          if (res.status === 200) {
            if (api.indexOf('36847f3f') > -1) {
              setTimeout(() => {
                resolve(res.data)
              }, 5000)
            } else {
              resolve(res.data)
            }
          } else {
            reject('error api')
          }
        })
      })
    },
  },
})

希望藉由上述三个不同的简单实例,能让大家更了解Promise的运作模式


<<:  EasyFlow 传送表单回Tiptop错误讯息显示:找不到指定的服务主机

>>:  Forti是否可做到快速收拢?

[Day 21] 过滤器Filter哗啦啦

今天天气真好,最适合来学习新事物了!!在创建一个网页时,有可能会遇到需要把使用者输入的文字转成大小写...

入门魔法 - 常用阵列方法(二)find、findIndex

前情提要 艾草:「不知不觉也累积了不少魔力总量了,我们今天透过魔法阵列来找出你适合的属性值吧!」 「...

【在 iOS 开发路上的大小事-Day07】除了用 WKWebView 以外,还可以如何在 App 中显示 PDF 档案呢?

前情提要 一般我们要在 App 中显示 PDF 档案,可能会透过 WKWebView 来进行实作 最...

【Day 29】Hook 09:自定义 Hook(Custom hook)

打造自己的 Hook 自 React 16.8 以後, 使用者就可以在 React 中 创建自定义的...

资料结构和演算法

https://wolkesau.medium.com/资料结构和演算法-c3a453c9c64c ...