成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Generator 詳解(使用場景,babel 轉(zhuǎn)譯,協(xié)程,異步,上層應用,async/await)

raise_yang / 2654人閱讀

摘要:不需要多線程的鎖機制線程由系統(tǒng)控制切換,協(xié)程是由用戶控制切換。協(xié)程的中斷實際上是掛起的概念協(xié)程發(fā)起異步操作意味著該協(xié)程將會被掛起,為了保證喚醒時能正常運行,需要正確保存并恢復其運行時的上下文。

博客 github 地址: https://github.com/HCThink/h-blog/blob/master/js/syncAndAsync/generator/readme.md

github 首頁(star+watch,一手動態(tài)直達): https://github.com/HCThink/h-blog

掘金 link , 掘金 專欄

segmentfault 主頁

原創(chuàng)禁止私自轉(zhuǎn)載

Generator
可以隨心所欲的交出和恢復函數(shù)的執(zhí)行權(quán),yield交出執(zhí)行權(quán),next()恢復執(zhí)行權(quán)

Generator 函數(shù)是一個狀態(tài)機,封裝了多個內(nèi)部狀態(tài),執(zhí)行一個Generator函數(shù)會返回一個迭代器對象,可以依次遍歷 Generator 函數(shù)內(nèi)部的每一個狀態(tài)

調(diào)用一個生成器函數(shù)并不會馬上執(zhí)行它里面的語句,而是返回一個這個 generator 的 迭代器 (iterator )對象。當這個迭代器的 next() 方法被首次(后續(xù))調(diào)用時,其內(nèi)的語句會執(zhí)行到第一個(后續(xù))出現(xiàn)yield的位置為止,yield 后緊跟迭代器要返回的值。

或者如果用的是 yield*(多了個星號),則表示將執(zhí)行權(quán)移交給另一個生成器函數(shù)(當前生成器暫停執(zhí)行)。

next()方法返回一個對象,這個對象包含兩個屬性:value 和 done,value 屬性表示本次 yield 表達式的返回值,done 屬性為布爾類型,表示生成器后續(xù)是否還有 yield 語句,即生成器函數(shù)是否已經(jīng)執(zhí)行完畢并返回。

典型場景

co

async/await

依賴 async 的上層庫和應用不勝枚舉,比如 koa

koa 等依賴其上層語法糖封裝: koa

基本使用 code

function* 這種聲明方式(function關(guān)鍵字后跟一個星號)會定義一個生成器函數(shù) (generator function),它返回一個 Generator 對象。

更多 demo 參考: 迭代器 , 常見數(shù)列生成器
// 斐波那契豎列生成器
function* fib() {
    let [x, y]: [number, number] = [0, 1];
    while (true) {
      [x, y] = [y, x + y];
      yield x;
    }
}

const generator: Generator = fib();

// 階乘
function* factorial() {
    let x: number = 1;
    let fac: number = 1;
    while (true) {
        yield fac;
        fac = fac * ++x;
    }
}
Generator 對象

調(diào)用一個生成器函數(shù)并不會馬上執(zhí)行它里面的語句,而是返回這個生成器的 迭代器 (實現(xiàn) iterator )的對象 Generator, 所以它符合可迭代協(xié)議和迭代器協(xié)議。如上述代碼中 const generator: Generator = fib(); 接受 fib() 的類型即: Generator

Generator 對象

Generator.prototype.next()

返回一個由 yield表達式生成的值。

Generator.prototype.return()

返回給定的值并結(jié)束生成器。

Generator.prototype.throw()

向生成器拋出一個錯誤。
yield 優(yōu)先級

操作符優(yōu)先級匯總

yield 僅僅比 展開運算符: ..., 逗號: , 的優(yōu)先級高,所以注意區(qū)分 yield fn() + 10fn() + 10 才是 yield 表達式。

generator 中斷 的入?yún)⒑头祷?/b>

generator 入?yún)⒎祷?/p>

注意,不是要說整個 generator 的出入?yún)ⅲ?yield 和 next,這個問題,其實困擾我蠻久的,原因是 generator 和傳統(tǒng) js 的函數(shù)調(diào)用區(qū)別很大, 如果你很熟悉普通函數(shù)調(diào)用的出入?yún)?在這里往往轉(zhuǎn)不過彎。

返回: next() 返回類 { done: boolean, value: any } 對象, 其中 value 則是 yield 表達式的值。

實際上返回會好理解一些,當我們執(zhí)行 generator 函數(shù)之后獲得一個 Generator 對象當我們第一次調(diào)用 GeneratorObj.next() 時,函數(shù)才會開始執(zhí)行,直到第一個 yield 表達式執(zhí)行完成, 并將 yield 表達式結(jié)果提供給 next 進行返回。【注意 yield 表達式此時開始執(zhí)行】,然后進入中斷。

function pi(n: number): number {
    return Math.PI * n;
}

function* fn(n: number) {
    // 第一個 next 調(diào)用后 yield 表達式【pi(n) + 10, 注意優(yōu)先級】執(zhí)行并將結(jié)果: 13.1415... 進行包裝
    // { value: 13.14..., done: false }
    let g1 = yield pi(n) + 10;
    // 同理這里就是: { value: 3.141592653589793, done: false }
    g1 = (yield pi(n)) + 10;

    // return 等價一最后一個 yield。
    return 100;
}

const fnGenx: Generator = fn(1);
Log(fnGenx.next());         // { value: 13.141592653589793, done: false }
Log(fnGenx.next());         // { value: 3.141592653589793, done: false }
Log(fnGenx.next());         // { value: 100, done: true }

當在生成器函數(shù)中顯式 return 時,會導致生成器立即變?yōu)橥瓿蔂顟B(tài),即調(diào)用 next() 方法返回的對象的 done 為 true。如果 return 后面跟了一個值,那么這個值會作為當前調(diào)用 next() 方法返回的 value 值。

調(diào)用 next 時會立即獲得 yield 表達式的執(zhí)行結(jié)果。也就是說 yield 不能多帶帶處理異步,因為 yield 其實不在意其后的表達式所有代碼執(zhí)行結(jié)束的時間點。因此也無法確定下次 next 的調(diào)用時間點。

入?yún)? next 方法也可以通過接受一個參數(shù)用以向生成器傳值。請注意,首次調(diào)用 next 方法時參數(shù)會被丟棄。next 入?yún)⒁?guī)則如下:

調(diào)用 next()方法時,如果傳入了參數(shù),那么這個參數(shù)會作為上一條執(zhí)行的 yield 語句的返回值

實際上往往會誤認為 let g1 = (yield x10(n)) + 10; 中 yield 表達式的值就會直接賦值給 g1 其實并不是這樣的,yield 表達式的值是 next 的返回值,當下次 next(100) 傳入的值會替代上一個 yield 表達式的值。也就等價于 g1 = (100) + 10

function x10(n: number): number {
    return 10 * n;
}

function* fn(n: number) {
    // yield x10(n) + 10 結(jié)果為:30, 下次 next 時傳入的值做了 +10, 則 g1 值為: 40
    let g1 = yield x10(n) + 10;
    Log(g1);            // 40
    // 同理: (yield x10(g1)) 結(jié)果為: 40 * 10 = 400, 下次 next 時傳入的值: 400 + 10 = 410
    // 代入中斷的點: g1 = 410(yield x10(g1)) + 10 =  420
    g1 = (yield x10(g1)) + 10;
    Log(g1);            // 420
}

// 第一個參數(shù)由生成器提供
const fnGenx: Generator = fn(2);
let genObj = fnGenx.next(100);    // 第一次入?yún)粊G棄, 因為他沒有上一個 yield

while (!genObj.done) {
    Log("outer: ", genObj.value);
    genObj = fnGenx.next(genObj.value + 10);
}

// outer:  30
// 40
// outer:  400
// 420
一個官方 demo
/** gen函數(shù)運行解析:
 * i=0 時傳入?yún)?shù)(0),并將參數(shù)0賦給上一句yield的返回賦值,由于沒有上一句yield語句,這步被忽略
 * 執(zhí)行var val =100,然后執(zhí)行yield val,此時g.next(i)返回{ value: 100, done: false }
 * 然后console.log(i,g.next(i).value),打印出0 100
 *
 * i=1 時傳入?yún)?shù)(1),并將參數(shù)1賦給上一句yield的返回賦值,即(val = 1)
 * 然后執(zhí)行console.log(val),打印出1。
 * 接著進入第二次while循環(huán),調(diào)用yield val,此時g.next(i)返回{ value: 1, done: false }
 * 然后console.log(i,g.next(i).value),打印出1 1
 *
 * i=2 ....(省略)
 */
function* gen() {
   var val =100;
   while(true) {
      val = yield val;
      console.log(val);
   }
}

var g = gen();
for(let i =0;i<5;i++){
   console.log(i,g.next(i).value);
}

// 返回:
//  0 100
//  1
//  1 1
//  2
//  2 2
//  3
//  3 3
//  4
//  4 4

yield*

如果 yield* Generator, 可以等價認為將 這個 Generator 的所有 yield 插入到 當前位置

function* anotherGenerator(i) {
    yield i + 1;
    yield i + 2;
    yield i + 3;
}

function* generator(i){
    yield i;
    yield* anotherGenerator(i);// 移交執(zhí)行權(quán)
    yield i + 10;
}

// 等價于
function* generator(i){
    yield i;
    //   yield* anotherGenerator(i);// 移交執(zhí)行權(quán)
    yield i + 1;
    yield i + 2;
    yield i + 3;
    yield i + 10;
}
注意點

next 的參數(shù)會作為上一條執(zhí)行的 yield 語句的返回值: let first = yield 1; 中 first 不是直接賦值為 yield 表達式的值, 而是 下次 next 傳入的值。

生成器函數(shù)不能當做構(gòu)造器使用。

function* f() {}
var obj = new f; // throws "TypeError: f is not a constructor"

yield 表達式是立即執(zhí)行的,并且返回表達式值, 如果 yield 表達式是異步的,你需要在恰當?shù)臅r機觸發(fā) next 才能達到 async 的執(zhí)行順序。在『重要問題 generator & 異步』中有詳細講解

generator 和異步機制不同,只是配合 generator + 執(zhí)行器可以 "同步化" 處理異步, Generator 函數(shù)是ES6提供的一種異步編程解決方案

“中斷”是 Generator 的重要特征 ———— Generator 能讓一段程序執(zhí)行到指定的位置先中斷,啟動。

babel 轉(zhuǎn)譯

參考: demo

function *gen(p) {
  console.log(p)
  const de1 = yield fn(p);
  console.log(de1)
  const de2 = yield fn(de1);
  console.log(de2)
}

function fn(p) {
    return Math.random() * p;
}

通過 babel 編譯為

"use strict";
var _marked = /*#__PURE__*/regeneratorRuntime.mark(gen);
function gen(p) {
  var de1, de2;
  return regeneratorRuntime.wrap(function gen$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          console.log(p);
          _context.next = 3;
          return fn(p);
        case 3:
          de1 = _context.sent;
          console.log(de1);
          _context.next = 7;
          return fn(de1);
        case 7:
          de2 = _context.sent;
          console.log(de2);
        case 9:
        case "end":
          return _context.stop();
      }
    }
  }, _marked, this);
}

function fn(p) {
  return Math.random() * p;
}

可以看到 babel 使用了一個諸如的對象: regeneratorRuntime 在不支持的環(huán)境 polyfill,這個對象解析出現(xiàn)在 babel 的 babel-plugin-transform-runtime 插件中.

插件目錄

source

const moduleName = injectCoreJS2
    ? "@babel/runtime-corejs2"
    : "@babel/runtime";
let modulePath = moduleName;

if (node.name === "regeneratorRuntime" && useRuntimeRegenerator) {
    path.replaceWith(
    this.addDefaultImport(
        `${modulePath}/regenerator`,
        "regeneratorRuntime",
    ),
    );
    return;
}

繼續(xù)跟進到 babel-runtime-corejs2/regenerator/index.js, babel-runtime/regenerator/index.js 文件中, 兩個文件均只有一行代碼: module.exports = require("regenerator-runtime"); 都使用了 fackbook 的 regenerator

regenerator

regenerator 源碼分析參考

支撐思想: 協(xié)程
協(xié)程,又稱微線程,纖程. 是一種非搶占式資源調(diào)度單元, 是一個無優(yōu)先級的輕量級的用戶態(tài)線程
前期知識準備

現(xiàn)代操作系統(tǒng)是分時操作系統(tǒng),資源分配的基本單位是進程,CPU調(diào)度的基本單位是線程。

簡單來說,進程(Process), 線程(Thread)的調(diào)度是由操作系統(tǒng)負責,線程的睡眠、等待、喚醒的時機是由操作系統(tǒng)控制,開發(fā)者無法精確的控制它們。使用協(xié)程,開發(fā)者可以自行控制程序切換的時機,可以在一個函數(shù)執(zhí)行到一半的時候中斷執(zhí)行,讓出CPU,在需要的時候再回到中斷點繼續(xù)執(zhí)行。

上下文: 指的是程序在執(zhí)行中的一個狀態(tài)。通常我們會用調(diào)用棧來表示這個狀態(tài)——棧記載了每個調(diào)用層級執(zhí)行到哪里,還有執(zhí)行時的環(huán)境情況等所有有關(guān)的信息。

調(diào)度: 指的是決定哪個上下文可以獲得接下去的CPU時間的方法。

進程: 是一種古老而典型的上下文系統(tǒng),每個進程有獨立的地址空間,資源句柄,他們互相之間不發(fā)生干擾。

線程: 是一種輕量進程,實際上在linux內(nèi)核中,兩者幾乎沒有差別,除了線程并不產(chǎn)生新的地址空間和資源描述符表,而是復用父進程的。 但是無論如何,線程的調(diào)度和進程一樣,必須陷入內(nèi)核態(tài)。

協(xié)程

傳統(tǒng)的編程語言,早有多任務的解決方案,其中有一種叫做"協(xié)程"(coroutine),意思是多個線程互相協(xié)作,完成異步任務, 這和普通的搶占式線程有所不同。

JS 中 generator 就類似一個語言層面實現(xiàn)的非搶占式的輕量級"線程"。 線程包含于進程,而協(xié)程包含于線程

所以協(xié)程具有極高的執(zhí)行效率。因為子程序切換不是線程切換,而是由程序自身控制,因此,沒有線程切換的開銷,和多線程比,線程數(shù)量越多,協(xié)程的性能優(yōu)勢就越明顯。

不需要多線程的鎖機制

線程由系統(tǒng)控制切換,協(xié)程是由用戶控制切換。

從更高的層面來講,協(xié)程和多線程是兩種解決“多任務”編程的技術(shù)。多線程使得 "同一時刻貌似" 有多個線程在并發(fā)執(zhí)行,不過需要在多個線程間協(xié)調(diào)資源,因為多個線程的執(zhí)行進度是“不可控”的。而協(xié)程則避免了多線程的問題,同一時刻實質(zhì)上只有一個“線程”在執(zhí)行,所以不會存在資源“搶占”的問題。

不過在 JS 領(lǐng)域,貌似不存在技術(shù)選擇的困難,因為 JS 目前還是“單線程”的,所以引入?yún)f(xié)程也是很自然的選擇吧。

協(xié)程 & 函數(shù)棧

大多語言都是層級調(diào)用,比如A調(diào)用B,B在執(zhí)行過程中又調(diào)用了C,C執(zhí)行完畢返回,B執(zhí)行完畢返回,最后是A執(zhí)行完畢。所以子程序調(diào)用是通過棧實現(xiàn)的,一個線程就是執(zhí)行一個子程序。子程序調(diào)用總是一個入口,一次返回,調(diào)用順序是明確的。

而協(xié)程的調(diào)用和子程序不同。協(xié)程看上去也是子程序,但執(zhí)行過程中,在子程序內(nèi)部可中斷,然后轉(zhuǎn)而執(zhí)行別的子程序,在適當?shù)臅r候再返回來接著執(zhí)行。

協(xié)程的中斷: 實際上是掛起的概念

協(xié)程發(fā)起異步操作意味著該協(xié)程將會被掛起,為了保證喚醒時能正常運行,需要正確保存并恢復其運行時的上下文。記錄步驟為:

保存當前協(xié)程的上下文(運行棧,返回地址,寄存器狀態(tài))

設置將要喚醒的協(xié)程的入口指令地址到IP寄存器

恢復將要喚醒的協(xié)程的上下文

可以參考 libco 騰訊開源的一個C++協(xié)程庫,作為微信后臺的基礎庫,經(jīng)受住了實際的檢驗: libco

JS 協(xié)程: generator

js 的生成器也是一種特殊的協(xié)程,它擁有 yield 原語,但是卻不能指定讓步的協(xié)程,只能讓步給生成器的調(diào)用者或恢復者。由于不能多個協(xié)程跳來跳去,生成器相對主執(zhí)行線程來說只是一個可暫停的玩具,它甚至都不需要另開新的執(zhí)行棧,只需要在讓步的時候保存一下上下文就好。因此我們認為生成器與主控制流的關(guān)系是不對等的,也稱之為非對稱協(xié)程(semi-coroutine)。

因此一般的協(xié)程實現(xiàn)都會提供兩個重要的操作 Yield 和 Resume(next)。

Generator 實現(xiàn)協(xié)程的問題

在協(xié)程執(zhí)行中不能有阻塞操作,否則整個線程被阻塞(協(xié)程是語言級別的,線程,進程屬于操作系統(tǒng)級別)

需要特別關(guān)注全局變量、對象引用的使用

yield 僅能存在于 生成器內(nèi)部[對比 node-fibers]

真.協(xié)程

所謂的真協(xié)程是相對 generator 而言的, node-fibers 庫提供了對應的實現(xiàn),我們用一個例子部分代碼說明二者區(qū)別

import Fiber from "fibers"
function fibersCo () {    /* 基于 fibers 的執(zhí)行器 ..... */    }
fibersCo(() => {
    let foo1 = a => {
        console.log("read from file1");
        let ret = Fiber.yield(a);
        return ret;
    };
    let foo2 = b => {
        console.log("read from file2");
        let ret = Fiber.yield(b);
        return ret;
    };
    let getSum = () => {
        let f1 = foo1(readFile("/etc/fstab"));
        let f2 = foo2(readFile("/etc/shells"));
        return f1.toString().length + f2.toString().length;
    };

    let sum = getSum();
});

通過這個代碼可以發(fā)現(xiàn),在第一次中斷被恢復的時候,恢復的是一系列的執(zhí)行棧!從棧頂?shù)綏5滓来螢椋篺oo1 => getSum => fibersCo 里的匿名函數(shù);而使用生成器,我們就無法寫出這樣的程序,因為 yield 原語只能在生產(chǎn)器內(nèi)部使用, SO

無論什么時候被恢復,都是簡單的恢復在生成器內(nèi)部,所以說生成器的中斷是不開調(diào)用棧滴。
重要問題 generator & 異步

generator 處理異步

generator 機制和異步有所不同, Generator 和普通函數(shù)本質(zhì)區(qū)別在于 Generator 能讓一段程序執(zhí)行到指定的位置,然后交出執(zhí)行棧,調(diào)用下次 next 的時候又會從之前中斷的位置繼續(xù)開始執(zhí)行,配合這種機制處理異步,則會產(chǎn)生同步化異步處理的效果。

generator 的問題

但其實很快發(fā)現(xiàn) generator 不能多帶帶處理異步問題,原因在于

generator 無法獲取下次 next 的時機。

generator 無法自執(zhí)行

generator 處理異步的思路 + 實踐

使用 Generator 函數(shù)來處理異步操作的基本思想就是在執(zhí)行異步操作時暫停生成器函數(shù)的執(zhí)行,然后在階段性異步操作完成的狀態(tài)中通過生成器對象的next方法讓Generator函數(shù)從暫停的位置恢復執(zhí)行,如此往復直到生成器函數(shù)執(zhí)行結(jié)束。簡單來講其實就是將異步串行化了。

也正是基于這種思想,Generator函數(shù)內(nèi)部才得以將一系列異步操作寫成類似同步操作的形式,形式上更加簡潔明了。

而要讓Generator函數(shù)按順序自動完成內(nèi)部定義好的一系列異步操作,還需要配套的執(zhí)行器。與之配套的有兩種思路

thunk

promise

其實在 async/await 之前就已經(jīng)有了 co 庫使用此兩種方案實現(xiàn)類似 async 的機制。參考 co 源碼分析

co 源碼分析

優(yōu)勢: 異常捕獲。 generator 的異常捕獲模型,優(yōu)于 promise。

function* gen(x){
  try {
    var y = yield x + 2;
  } catch (e){
    console.log(e);
  }
  return y;
}
generator 的 yield 會產(chǎn)生調(diào)用函數(shù)棧么?

因為 yield 原語只能在生產(chǎn)器內(nèi)部使用, 所以無論什么時候被恢復,都是簡單的恢復在生成器內(nèi)部。所以說生成器的中斷是不開調(diào)用棧滴。

參考上述章節(jié)

真.協(xié)程

中斷/函數(shù)棧

上層應用

async / await

async / await, co

并發(fā)通信: 多個generator函數(shù)結(jié)合在一起,讓他們獨立平行的運行,并且在它們執(zhí)行的過程中來來回回得傳遞信息

csp : 并行(多個 generator 微線程通訊)

參考

function* api

Generator api

https://cnodejs.org/topic/58d...

https://www.cnblogs.com/wangf...

https://github.com/Jocs/jocs....

https://cnodejs.org/topic/58d...

https://brooch.me/2016/12/30/...

https://blog.csdn.net/shenlei...

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/100012.html

相關(guān)文章

  • js學習之異步處理

    摘要:學習開發(fā),無論是前端開發(fā)還是都避免不了要接觸異步編程這個問題就和其它大多數(shù)以多線程同步為主的編程語言不同的主要設計是單線程異步模型。由于異步編程可以實現(xiàn)非阻塞的調(diào)用效果,引入異步編程自然就是順理成章的事情了。 學習js開發(fā),無論是前端開發(fā)還是node.js,都避免不了要接觸異步編程這個問題,就和其它大多數(shù)以多線程同步為主的編程語言不同,js的主要設計是單線程異步模型。正因為js天生的與...

    VioletJack 評論0 收藏0
  • 記一次小程序開發(fā)中如何使用async-await并封裝公共異步請求

    摘要:實現(xiàn)方案首先小程序目前還是不支持的和的,那么如何讓它支持呢點擊下載,并把下載好的文件夾放到自己小程序的目錄下,包總共才多,體積很小的。如果想使用這些新的對象和方法,必須使用,為當前環(huán)境提供一個墊片。用于實現(xiàn)瀏覽器并不支持的原生的代碼。 前言 在平常的項目開發(fā)中肯定會遇到同步異步執(zhí)行的問題,還有的就是當執(zhí)行某一個操作依賴上一個執(zhí)行所返回的結(jié)果,那么這個時候你會如何解決這個問題呢; 1.是...

    why_rookie 評論0 收藏0
  • JavaScript 與 異步編程

    摘要:然而異步編程真正發(fā)展壯大,的流行功不可沒。于是從異步編程誕生的那一刻起,它就和回調(diào)函數(shù)綁在了一起。這個函數(shù)會起一個定時器,在超過指定時間后執(zhí)行指定的函數(shù)。我們知道是異步編程的未來。 什么是異步(Asynchrony) 按照維基百科上的解釋:獨立于主控制流之外發(fā)生的事件就叫做異步。比如說有一段順序執(zhí)行的代碼 void function main() { fA(); fB(); }...

    YFan 評論0 收藏0
  • 一篇文章了解前端異步編程方案演變

    摘要:對于而言,異步編程我們可以采用回調(diào)函數(shù),事件監(jiān)聽,發(fā)布訂閱等方案,在之后,又新添了,,的方案??偨Y(jié)本文闡述了從回調(diào)函數(shù)到的演變歷史。參考文檔深入掌握異步編程系列理解的 對于JS而言,異步編程我們可以采用回調(diào)函數(shù),事件監(jiān)聽,發(fā)布訂閱等方案,在ES6之后,又新添了Promise,Genertor,Async/Await的方案。本文將闡述從回調(diào)函數(shù)到Async/Await的演變歷史,以及它們...

    lmxdawn 評論0 收藏0
  • async/await 更好的異步解決方案

    摘要:大家都一直在嘗試使用更好的方案來解決這些問題。這是一個用同步的思維來解決異步問題的方案。當我們發(fā)出了請求,并不會等待響應結(jié)果,而是會繼續(xù)執(zhí)行后面的代碼,響應結(jié)果的處理在之后的事件循環(huán)中解決。我們可以用一個兩人問答的場景來比喻異步與同步。 在實際開發(fā)中總會遇到許多異步的問題,最常見的場景便是接口請求之后一定要等一段時間才能得到結(jié)果,如果遇到多個接口前后依賴,那么問題就變得復雜。大家都一直...

    Ali_ 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<