1. 程式人生 > >typescript在ES3(IE7)環境下使用async、await

typescript在ES3(IE7)環境下使用async、await

back dex mail generator don http -s sync test

因為公司產品需要搞個Web App,但是又需要兼容IE7,這時候整個應用會非常復雜,尤其是在處理異步的時候,在我的選擇中有兩個方案

  1. callback方案
  2. async/await

經過衡量以後,決定使用async/await方案

配置typescript環境

$ mkdir typescript-async            # 新建項目目錄
$ cd typescript-async               # 進入項目目錄
$ npm init -y                       # 初始化項目
$ npm i webpack --save-dev          # 安裝webpack
$ npm i ts-loader --save-dev        # 安裝loader
$ npm i typescript --save-dev       # 安裝typescript編譯器
$ npm i es3ify-webpack-plugin --save-dev
$ touch webpack.dev.js              # 新建webpack配置文件
$ .\node_modules\.bin\tsc --init    # 創建typescript配置文件

webpack.dev.js改為如下

const path = require(‘path‘);
const es3ifyPlugin = require(‘es3ify-webpack-plugin‘);

module.exports = {
    mode: ‘development‘,
    entry: ‘./src/index.ts‘,
    output: {
        path: path.resolve(__dirname, ‘build‘),
        filename: ‘[name].js‘,
    },
    module: {
        rules: [{
            test: /\.ts$/,
            use: [‘ts-loader‘],
        }],
    },
    resolve: {
        extensions: [‘.ts‘],
    },
    devtool: "source-map",
    plugins: [
        new es3ifyPlugin(),
    ],
};

package.json修改為如下

{
    // ...
    "scripts": {
-       "test": "echo \"Error: no test specified\" && exit 1",
+       "start": "webpack --config webpack.dev.js"
    }
    // ...
}

tsconfig.json修改為如下

{
    "compilerOptions": {
        // ...
-      "target": "es5",
+      "target": "es3",
        // ...
-      "strict": true,
+      "strict": false,
        // ...
    }
}

配置測試

$ mkdir src
$ touch src/index.ts            # 新建文件

index.ts改為如下

const log = (text: string) => console.log(text);

for (let i = 0; i < 5; i++) {
    log(String(i));
}

編譯源碼

$ npm start

只要沒有報錯,就可以在看到build/main.js文件,這個文件就是編譯後的結果,那麽typescript的編譯環境就搭建好了

支持async、await

$ npm i es6-promise --save          # 安裝promise polyfill

webpack.dev.js改為如下

module.exports = {
    // ...
    resolve: {
-       extensions: [‘.ts‘],
+       extensions: [‘.js‘, ‘.ts‘],
    },
    // ...
};

tsconfig.json修改為如下

{
    "compilerOptions": {
        // ...
+       "lib": [
+           "dom",
+           "es2015",
+           "scripthost"
+       ], 
        // ...
    }
}

src/index.ts改為如下

import "es6-promise/auto";          // 低版本瀏覽器支持promise

const delay = (time: number) => new Promise(resolve => setTimeout(resolve, time));

(async () => {
    await delay(1000);
    alert(‘done.‘);
})();

編譯源碼

$ npm start

編譯成功,async/await在ES3的環境下可以使用了

優化helpers代碼

什麽是helpers代碼?直接看例子,有以下代碼

src/index.ts改為如下

import "es6-promise/auto";
import delayA from "./a";
import delayB from "./b";

const delay = (time: number) => new Promise(resolve => setTimeout(resolve, time));

(async () => {
    await delay(1000);
    alert(‘1‘);
    await delayA(1000);
    alert(‘2‘);
    await delayB(1000);
    alert(‘3‘);
})();

src/a.ts改為如下

const delay = (time: number) => new Promise(resolve => setTimeout(resolve, time));

async function delayA(time: number) {
    await delay(time);
}

export default delayA;

src/b.ts改為如下

const delay = (time: number) => new Promise(resolve => setTimeout(resolve, time));

async function delayB(time: number) {
    await delay(time);
}

export default delayB;

編譯源碼

$ npm start

查看生成後的代碼build/main.js,會看到有以下部分

// 省略以上代碼

/************************************************************************/
/******/ ({

/***/ "./src/a.ts":
/*!******************!*  !*** ./src/a.ts ***!
  \******************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    // ...省略
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    // ...省略    
};
exports.__esModule = true;
var delay = function (time) { return new Promise(function (resolve) { return setTimeout(resolve, time); }); };
function delayA(time) {
    return __awaiter(this, void 0, void 0, function () {
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, delay(time)];
                case 1:
                    _a.sent();
                    return [2 /*return*/];
            }
        });
    });
}
exports["default"] = delayA;


/***/ }),

/***/ "./src/b.ts":
/*!******************!*  !*** ./src/b.ts ***!
  \******************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    // ...省略
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    // ...省略    
};
exports.__esModule = true;
var delay = function (time) { return new Promise(function (resolve) { return setTimeout(resolve, time); }); };
function delayB(time) {
    return __awaiter(this, void 0, void 0, function () {
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0: return [4 /*yield*/, delay(time)];
                case 1:
                    _a.sent();
                    return [2 /*return*/];
            }
        });
    });
}
exports["default"] = delayB;


/***/ }),

/***/ "./src/index.ts":
/*!**********************!*  !*** ./src/index.ts ***!
  \**********************/
/*! no static exports found */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    // ...省略
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    // ...省略    
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _this = this;
exports.__esModule = true;
__webpack_require__(/*! es6-promise/auto */ "./node_modules/es6-promise/auto.js");
var a_1 = __importDefault(__webpack_require__(/*! ./a */ "./src/a.ts"));
var b_1 = __importDefault(__webpack_require__(/*! ./b */ "./src/b.ts"));
var delay = function (time) { return new Promise(function (resolve) { return setTimeout(resolve, time); }); };
(function () { return __awaiter(_this, void 0, void 0, function () {
    return __generator(this, function (_a) {
        switch (_a.label) {
            case 0: return [4 /*yield*/, delay(1000)];
            case 1:
                _a.sent();
                alert(‘1‘);
                return [4 /*yield*/, a_1["default"](1000)];
            case 2:
                _a.sent();
                alert(‘2‘);
                return [4 /*yield*/, b_1["default"](1000)];
            case 3:
                _a.sent();
                alert(‘3‘);
                return [2 /*return*/];
        }
    });
}); })();


/***/ })

/******/ });
//# sourceMappingURL=main.js.map

可以看到大量的重復的__awaiter__generator代碼,這個就是helpers代碼,我們需要去掉重復的代碼,處理的方式有以下兩種

方法1:importHelpers開關

$ npm i tslib --save          # 安裝tslib

tsconfig.json修改為如下

{
    "compilerOptions": {
        // ...
+       "importHelpers": true,
        // ...
    }
}

註:上面這種方式需要支持Object.defineProperty這個方法,但是ES3環境不支持,所以ES3環境下不能用這個方式

方法2:noEmitHelpers開關

$ npm i tslib --save          # 安裝tslib

tsconfig.json修改為如下

{
    "compilerOptions": {
        // ...
+       "noEmitHelpers": true,
        // ...
    }
}

src/index.ts改為如下

import "es6-promise/auto";
+ import ‘tslib/tslib‘;
// ...

編譯源碼

$ npm start

查看生成後的代碼build/main.js,可以看到重復的部分沒有了

以上就是整個在ES3環境下使用async/await的方法,如果有不懂的地方可以發郵件[email protected]聯系我

typescript在ES3(IE7)環境下使用async、await

typescript在ES3(IE7)環境下使用async、await