JavaScript 異步編程_035

JavaScript 異步編程

一道面試題

for(var i = 0; i < 3; i++) {
   setTimeout(function() {
       console.log('timeout' + i);
   })
}

new Promise(function(resolve) {
    console.log('promise1');
    for(var i = 0; i < 1000; i++) {
        i == 99 && resolve();
    }
    console.log('promise2');
}).then(function() {
    console.log('then1');
})

console.log('global1');


promise1
promise2
global1
then1
3 timeout3

JavaScript單線程

在瀏覽器的一個頁面中,該頁面的JS程序只有一個線程,故曰單線程。由於是單線程,因此程序的執行順序就是從上到下依次執行,同一時間內只能有一段代碼被執行。javascript

瀏覽器多進程

  • 瀏覽器是多進程的
  • 瀏覽器之因此可以運行,是由於系統給它的進程分配了資源(cpu、內存)
  • 簡單點理解,每打開一個Tab頁,就至關於建立了一個獨立的瀏覽器進程。
  • 瀏覽器的渲染進程是多線程的html

    • GUI渲染線程
    • JS引擎線程
    • 事件觸發線程
    • 定時觸發器線程
    • 異步http請求線程

瀏覽器渲染進程圖:
imgjava

異步機制

for (var i = 0; i < 5; i ++) {
        setTimeout(function(){
            console.log(i);
        }, 0);
    }
    console.log(i);
    //5 ; 5 ; 5 ; 5; 5

回調函數Callback

這是異步編程最基本的方法。面試

假定有兩個函數f1和f2,後者等待前者的執行結果。編程

  f1();

  f2();

若是f1是一個很耗時的任務,能夠考慮改寫f1,把f2寫成f1的回調函數。\promise

  function f1(callback){
    setTimeout(function () {
      // f1的任務代碼
      callback();
    }, 1000);
  }

執行代碼就變成下面這樣:瀏覽器

 f1(f2);

採用這種方式,咱們把同步操做變成了異步操做,f1不會堵塞程序運行,至關於先執行程序的主要邏輯,將耗時的操做推遲執行。多線程

回調函數的優勢是簡單、容易理解和部署,缺點是不利於代碼的閱讀和維護,各個部分之間高度耦合Coupling,流程會很混亂,並且每一個任務只能指定一個回調函數。app

發佈訂閱

發佈-訂閱模式又叫作觀察者模式,他定義了一種一對多的依賴關係,即當一個對象的狀態發生改變的時候,全部依賴他的對象都會獲得通知。異步

let yourMsg = {};
yourMsg.peopleList = [];
yourMsg.listen = function (fn) {
    this.peopleList.push(fn);
}
yourMsg.triger = function () {
    for(var i = 0,fn;fn=this.peopleList[i++];){
        fn.apply(this,arguments);
    }
}

yourMsg.listen(function (name) {
    console.log(`${name}收到了你的消息`);
})
yourMsg.listen(function (name) {
    console.log('哈哈');
})

yourMsg.triger('張三');
yourMsg.triger('李四');

Promise

Promise 是一個對象,它表明了一個異步操做的最終完成或者失敗。

Promise 最直接的好處就是鏈式調用(chaining

const promise = new Promise(function(resolve, reject) {
  // ... some code

  if (/* 異步操做成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

生成器Generators/ yield

Generator

function* Hello() {
    yield 100
    yield (function () {return 200})()
    return 300
}

var h = Hello()
console.log(typeof h)  // object

console.log(h.next())  // { value: 100, done: false }
console.log(h.next())  // { value: 200, done: false }
console.log(h.next())  // { value: 300, done: true }
console.log(h.next())  // { value: undefined, done: true }

yield

yield關鍵字使生成器函數執行暫停,yield關鍵字後面的表達式的值返回給生成器的調用者。它能夠被認爲是一個基於生成器的版本的return關鍵字。

function* countAppleSales () {
  var saleList = [3, 7, 5];
  for (var i = 0; i < saleList.length; i++) {
    yield saleList[i];
  }
}
var appleStore = countAppleSales(); // Generator { }
console.log(appleStore.next()); // { value: 3, done: false }
console.log(appleStore.next()); // { value: 7, done: false }
console.log(appleStore.next()); // { value: 5, done: false }
console.log(appleStore.next()); // { value: undefined, done: true }

async/await

async function func() {
    try {
        let res = await asyncFunc()
    } catch (e) {
      //......
    }
}

async 函數返回的 Promise 對象,必須等到內部全部的 await 命令的 Promise 對象執行完,纔會發生狀態改變

async 函數的語法不難,難在錯誤處理上。

https://juejin.im/post/5a6547...
http://www.ruanyifeng.com/blo...
https://juejin.im/post/5a1681...
https://juejin.im/post/5ce75f...
https://developer.mozilla.org...
https://juejin.im/post/596e14...
相關文章
相關標籤/搜索