haotech / Learning

4 stars 0 forks source link

第一期:Promise原理与使用 #1

Open zhaoyan1986 opened 8 years ago

zhaoyan1986 commented 8 years ago

刘博文,柏盼 2016年7月15日

Promise原理与使用

提前预习资料

https://www.promisejs.org/ http://liubin.org/promises-book/

教学大纲

  1. promise 的历史与规范
    1. 流程控制的演进过程
    2. 初识Promise
    3. Promise的三种状态
    4. Promise 流程控制
  2. promise API
    1. then / catch / done / finally
    2. Promise.resolve / Promise.reject
    3. Promise.all / Promise.race
    4. Promise.denodeify /nodeify
  3. 细节总结
  4. 不同实现的对比
    1. jQuery的实现 1.when的实现 1.ES6的实现
    2. promise 的最佳实践

      演讲目标

通过教学,让大家掌握Promise的整体原理,最佳实践,以及在项目中熟练使用

作业

使用Node和Promise的Api,实现以下需求。

  1. 使用 fs.writeFile fs.appendFile fs.readFile 加上promise api实现:
    • 先随便写点什么字符串到文件中
    • 随便写点什么追加到该文件中
    • 读取该文件中的内容,将内容打印到终端。
    • 要求:不能将一个异步操作写在另一个异步操作的回调函数中
  2. 使用request模块加上promise api实现:

promise反模式

huanhuan1989 commented 8 years ago
var path = require('path');
var fs = require('fs');
var request = require('request');
var express = require("express");
var __dirUrl = __dirname + '/views/pages/';

var port = process.env.PORT || 8080;   //端口号
var app = express();  // 创建项目实例
app.set('views', __dirUrl);// 设置模板引擎
app.set('view engine', 'html');// 设置模板相对路径(相对当前目录)

app.use(express.static(path.join(__dirname, 'static')));  //静态资源

//创建服务器
app.listen(port);

/**
 * 闲来,瞎搞。。。
var promiseHandlder = function (fn, receiver){
    return function (){
        var _args = Array.prototype.slice.call(arguments);
        return new Promise(function(resolve, reject) {
            var _newData = _args.concat(function (err, res){
                return err ? reject(err) : resolve(res && res.toString());
            });
            return fn.apply(receiver, _newData);
        });
    };
};

promiseHandlder(fs.writeFile, fs)(__dirUrl + 'demo-1.text', "Hello World")
    .then(function (){
        console.log('writeFile success');
    })
    .then(function() {
        return promiseHandlder(fs.appendFile, fs)(__dirUrl + 'demo-1.text', '\nsecond line');
    }).then(function (){
        console.log('appendFile success');
    })
    .then(function() {
        return promiseHandlder(fs.readFile, fs)(__dirUrl + 'demo-1.text');
    }).then(function (data){
        console.log(data);
    })
    .catch(function(err) {
        cosnole.log(err);
    });
*/

/**
 * 闲来,瞎搞。。。
*/
var promiseHandlder = function (fn, receiver, str, count){
    this.fn = fn,
    this.receiver = receiver;
    this.str = str || '';
    this.count = count || '';
    this.__utilsType();
};
promiseHandlder.prototype = {
    promisify: function (){
        var self = this;
        var _args = Array.prototype.slice.call(arguments);
        _args = (this.isEmptyObject(arguments)) ? [this.str, this.count] : (this.utilsType.isArray(_args[0]) ? _args[0]: _args);
        return new Promise(function(resolve, reject) {
            var _newData = _args.concat(function (err, res){
                return err ? reject(err) : resolve(res && res.toString());
            });
            return self.fn.apply(self.receiver, _newData);
        });
    },
    appendFile: function () {
        var args = Array.prototype.slice.call(arguments),
            _cont = this.isEmptyObject(args) ? this.cont : args;
        this.fn = this.receiver.appendFile;
        return this.promisify(_cont);
    },
    readFile: function (){
        var args = Array.prototype.slice.call(arguments),
            _cont = this.isEmptyObject(args) ? this.str : args;
        this.fn = this.receiver.readFile;
        return this.promisify(_cont);
    },
    isEmptyObject: function (obj){
        var key;
        for(key in obj){
            if(obj[key]){
                return !1;
            }
        }
        return !0;
    },
    utilsType: {},
    /**
     * __utilsType 保存所有的类型,并且判断是否是自己想要的类型
     * @param  utilsType   把对象保存在utilsType对象中。
     * @param  isArray: function (){}....
    */
    __utilsType: function () {
        var self = this,
            i = 0,
            typeArr = ['Array', 'Object', 'Null', 'undefined', 'Function'],
            typeLen = typeArr.length;
        for(; i < typeLen; i++ ){
            (function (index) {
                self.utilsType['is'+typeArr[index]] = function (info){
                    return Object.prototype.toString.call(info) == '[object '+ typeArr[index] +']';
                };
            })(i);
        };
        return this;
    }
};

var _objPromise = new promiseHandlder(fs.writeFile, fs, __dirUrl + 'demo-1.text', "Hello World");
_objPromise.promisify()
    .then(function (){
        console.log('writeFile success');
    })
    .then(_objPromise.appendFile(__dirUrl + 'demo-1.text', "Hello World111111"))
    .then(function (){
        console.log('appendFile success');
    })
    /**
     * 两种调方式都是可以的,下面也可行
     *
    .then(function (){
        return _objPromise.readFile();
    })
    */
    .then(_objPromise.readFile.bind(_objPromise)) 
    .then(function (data){
        console.log(data);
    })
    .catch(function(e) {
        cosnole.log(e.message);
    });

/**
 * http 请求 - Promise
*/
var promise_request = function (url, id) {
    this.url = url || '';
    this.id = id || '_id';
};
promise_request.prototype = {
    getInfo: function () {
        var self = this;
        return new Promise(function (resolve, reject) {
            return request(self.url, function (err, response, data) {
                if(!err && (response.statusCode >= 200 && response.statusCode < 300 || response.statusCode == 304)){
                    resolve(data);
                }else{
                    reject(err);
                }
            });
        });
    },
    readJSON: function (params) {
        return this.getInfo().then(JSON.parse);
    },
    getUserId: function () {
        var self = this;
        return this.readJSON().then(function (data) {
            return data[self.id];
        });
    }
};

/** 
 * 获取用户ID http://demos.so/result/homework.promise.userInfo
 * 用户发布过的帖子api地址   'http://demos.so/result/userid='+id
 * 用户学习过的帖子API地址   'http://demos.so/result/student='+id
*/
var req_str = {
    getUserId: function () {
        return new promise_request('http://demos.so/result/homework.promise.userInfo').getUserId().then();
    },
    post_t: function () {
        return this.getUserId().then(function (data){
            return new promise_request('http://demos.so/result/userid=' + data).getInfo().then(JSON.parse);
        });
    },
    study_t: function () {
        return this.getUserId().then(function (data){
            return new promise_request('http://demos.so/result/student=' + data).getInfo().then(JSON.parse);
        });
    },
    main: function (time){
        return Promise.all([this.post_t(), this.study_t()]);
    },
    race: function (time){
        return Promise.race([this.post_t(), this.study_t(), this.timeout(time)]);
    },
    timeout: function (time){
        var promise = new Promise(function(resolve, reject){
            setTimeout(function(){
                reject('请求超时了');
            }, time);
        });
        return promise;
    }
};

/**
 * main 里面封装的all, 
 * 两次贴子的进程同时发出,并返回相对应的结果
req_str.main().then(function (value){
    console.log('用户发布过的帖子----------------------------');
    console.dir(value[0]);
    console.log('------------------------------------------');
    console.log('用户学习过的帖子----------------------------');
    console.dir(value[1]);
}, function (err){
    console.log(err);
}).catch(function (err){
    console.log(err);
});
*/

/**
 * 使用race 传入时间来控制超时
 * 测试
 */
req_str.race(1000).then(function (value){
    console.log('谁快就显示谁喽----------------------------');
    console.log(value);
    console.log('------------------------------------------');
}, function (err){
    console.log(err);
}).catch(function (err){
    console.log(err);
});

//404
app.use(function (req, res, next){
    res.status(404).send('Sorry, we cannot find that!');
    //next();
});

//500
app.use(function(err, req, res, next){
    res.status(500).send({ error: 'something blew up' });
    //next();
});
dashixiong1990 commented 8 years ago
'use strict'
var fs = require('fs');

let getPromise = callback => {
    return new Promise((resolve, reject) => {
        callback(resolve, reject)
    })
}
// 读写插入文件
getPromise((resolve, reject) => {
    fs.writeFile('123.txt', 'hello world', (err) => {
        if (err) reject(err)
        console.log('写入成功')
        resolve()
    })
}).then(getPromise((resolve, reject) => {
    fs.appendFile('123.txt', ' dashixiong', (err) => {
        if (err) reject(err)
        console.log('插入成功');
        resolve()
    })
})).then((data) => {
    fs.readFile('123.txt', 'UTF-8', (err, data) => {
        if (err) reject(err)
        console.log(data)
    })
}).catch((error) => {
    console.log(error)
})

// 并行请求
let http = require('http');
let getRequestPromise = (url, callback) => {
    return getPromise((resolve, reject) => {
        http.request(url, (res) => {
            let data = '';
            res.setEncoding('utf8');
            res.on('data', (chunk) => {
                data += chunk;
            });
            res.on('end', () => {
                data = JSON.parse(data);
                callback(resolve, reject, data);
            })
        }).on('error', function(error) {
            reject(error)
        }).end();
    })
};

const idUrl = 'http://demos.so/result/homework.promise.userInfo';
getRequestPromise(idUrl, (resolve, reject, data) => {
    resolve(data._id);
}).then((data) => {
    const postUrl = `http://demos.so/result/userid=${data}`,
        learnUrl = `http://demos.so/result/student=${data}`;

    return Promise.all([
        getRequestPromise(postUrl, (resolve, reject, data) => {
            resolve(data);
        }),
        getRequestPromise(learnUrl, (resolve, reject, data) => {
            resolve(data);
        })
    ])
}).then(function(datas) {
    console.log(datas)
})

//超时
let xhr = null;
let getXHRPromise = (url) => {
    return getPromise((resolve, reject) => {
        xhr = new XMLHttpRequest();
        console.log(xhr)
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
                    resolve()
                } else {
                    reject('xhr')
                }
            }
        };
        xhr.open('get', url, true);
        xhr.send(null);
    })
}

let timeout = (time, promise) => {
    Promise.race([
        getPromise((resolve, reject) => {
            setTimeout(() => {
                reject(new Error('timeout'))
            }, time)
        }),
        promise
    ]).catch((error) => {
        if (error.message == 'timeout') {
            console.log('timeout')
            xhr.abort()
        }
    })
}

timeout(1000, getXHRPromise())
liuyuchenzh commented 8 years ago
var Promise = require("promise"),
    fs = require("fs"),
    request = require("request");

// hw1
var PromiseWrapper = function(fn) {
    return function() { // 使用...args报错
        var args = Array.prototype.slice.call(arguments);
        return new Promise(function(resolve, reject) {
            args.push(function(err, data) {
                if (err) {
                    reject(err);
                } else {
                    if (data) {
                        console.log(data.toString());
                    }
                    resolve(data);
                }
            });
            fn.apply(fs, args);
        });
    }
};

PromiseWrapper(fs.writeFile)("test.txt", "Hello World")
    .then(function() {
        PromiseWrapper(fs.appendFile)("test.txt", "\nHello Again");
    })
    .then(function() {
        PromiseWrapper(fs.readFile)("test.txt");
    })
    .catch(function(err) {
        cosnole.log(err);
    });

// hw2
var promiseAjax = function(url) {
    return new Promise(function(resolve, reject) {
        request(url, function(err, res, body) {
            if (!err && res.statusCode == 200) {
                resolve(body);
            } else {
                reject(err, res.statusCode);
            }
        });
    });
}

promiseAjax("http://demos.so/result/homework.promise.userInfo")
    .then(function(body) {
        var res = body;
        res = JSON.parse(res);
        return Promise.all([promiseAjax("http://demos.so/result/userid=" + res._id), promiseAjax("http://demos.so/result/student=" + res._id)]);
    })
    .then(function(arr) {
        console.log("hw2", arr);
    })
    .catch(function(err) {
        console.log(err);
    });

// extra
function timeout(time) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            reject("timeout");
        }, time);
    });
}

promiseAjax("http://demos.so/result/homework.promise.userInfo")
    .then(function(body) {
        var res = body;
        res = JSON.parse(res);
        var success = Promise.all([promiseAjax("http://demos.so/result/userid=" + res._id), promiseAjax("http://demos.so/result/student=" + res._id)]);
        var fail = timeout(1);
        return Promise.race([success, fail]);
    })
    .then(function(arr) {
        console.log(arr);
    })
    .catch(function(err) {
        console.log(err);
    });
xiamingxing commented 8 years ago
/* log.js */
"use strict";

import path from "path";

import fs from "fs";

import chalk from "chalk";

import moment from "moment";

const logPath = path.resolve(path.dirname(__dirname), "log");

const logStyle = {
    "success": "green",
    "warn": "red",
    "default": "green"
};

/**
 *
 * @param filename
 * @param data
 */
function writeLog(filename, data) {
    let fileFullPath = path.join(logPath, filename);

    fs.exists(fileFullPath, err => {
        if (err) {
            fs.appendFile(fileFullPath, data);
        }
        else {
            fs.writeFile(fileFullPath, data);
        }
    });
}

/**
 *
 * @param type
 */
function output(type) {
    let style = logStyle[type] || logStyle.default;

    if (typeof chalk[style] !== "function") {
        style = "green";
    }

    console.log.apply(console, Array.prototype.slice.call(arguments, 1).map(item => {
        return chalk[style](JSON.stringify(item));
    }));

    writeLog(`${moment().format("L").replace(/\//ig, "-")}.${type}.log`, Array.prototype.slice.call(arguments, 1).map(item => {
            return JSON.stringify(item);
        }).join("\t") + "\n");
}

/**
 * @param arguments
 */
function successLog() {
    output.apply(null, ["success", moment().format()].concat(Array.prototype.slice.call(arguments, 0)));
}

/**
 * @param arguments
 */
function warnLog() {
    output.apply(null, ["warn", moment().format()].concat(Array.prototype.slice.call(arguments, 0)));
}

module.exports = {output, successLog, warnLog};
/* spider.js */
"use strict";

import request from "request";

import Promise from "promise";

import EventEmitter from "events";

import fs from "fs";

import path from "path";

import cheerio from "cheerio";

import {exec} from "shelljs";

import {successLog, warnLog} from "./log";

/**
 * 数据存储路径
 * @type {string}
 */
const dataPath = path.resolve(path.dirname(__dirname), "data");

/**
 *
 * @param url
 * @returns {*}
 */
function crawleWebpage(url) {
    return new Promise((resolve, reject) => {
        request.get(url, {encoding: "utf8"}, (err, req, body) => {
            if (err) {
                reject(err);
            }
            else {
                resolve(body);
            }
        });
    });
}

/**
 *
 * @param content
 * @param filter
 * @returns {*}
 */
function convertWebpage(content, filter) {
    let $ = cheerio.load(content, {decodeEntities: false});
    $(filter.orgin).text(filter.target);
    return $.html();
}

/**
 *
 * @param key
 * @param filedata
 * @returns {*}
 */
function saveToLocal(filepath, filedata) {
    return new Promise((resolve, reject) => {
        fs.writeFile(filepath, filedata, err => {
            if (err) {
                reject(err);
            }
            else {
                resolve(filepath);
            }
        });
    });
}

/**
 *
 * @param key
 * @returns {*}
 */
function generateLocalPath(key) {
    return path.join(dataPath, key + "_" + new Date().getFullYear() + ".html");
}

/**
 *
 * @returns {*}
 */
function generateLogPath() {
    return path.join(dataPath, new Date().getFullYear() + ".json");
}

export default class SpiderPromise extends EventEmitter {
    /**
     *
     * @param conf
     */
    constructor(conf) {
        super();
        this.conf = Object.assign({}, conf);
    }

    /**
     *
     * @param config
     * @returns {*}
     */
    excuteTask(config) {
        return crawleWebpage(config.url)
            .then(content => {
                return convertWebpage(content, config.filter);
            })
            .then(filedata => {
                return saveToLocal(generateLocalPath(config.key), filedata);
            })
            .then(filepath => {
                config.filepath = filepath;
                return config;
            });

    }

    /**
     * runTasks
     */
    runTasks() {
        let self = this;

        successLog("spider任务开始");

        return Promise.
        all(this.conf.tasks.map(item => {
            return self.excuteTask(item);
        }))
            .then(res => {
                return saveToLocal(generateLogPath(), JSON.stringify(res));
            })
            .then(filepath => {
                successLog("task run complete!");
                exec("cat " + filepath);
            })
            .catch(err => {
                warnLog("task run fail!");
                warnLog(err);
            })
            .finally(() =>{
                successLog("spider任务结束");
            });
    }
}
/* api.js */
"use strict";

import request from "request";

import Promise from "promise";

import EventEmitter from "events";

import {successLog, warnLog} from "./log";

/**
 * 超时时间
 * @type {number}
 */
const timeout = 3000;

/**
 *
 * @param timeout
 * @returns {*}
 */
function timerDown(timeout) {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            reject("已超时");
        }, timeout);
    });
}

/**
 *
 * @param url
 * @returns {*}
 */
function get(url) {
    return new Promise((resolve, reject) => {
        request.get(url, {encoding: "utf8"}, (err, req, body) => {
            if (err) {
                reject(err);
            }
            else {
                resolve(JSON.parse(body));
            }
        });
    });
}

/**
 *
 * @param url
 * @returns {*}
 */
function fecthData(url) {
    return Promise.race([get(url), timerDown(timeout)]);
}

export default class ApiPromise extends EventEmitter {

    /**
     *
     * @param conf
     */
    constructor(conf) {
        super(conf);
        this.conf = Object.assign({}, conf);
    }

    /**
     *
     * @returns {*}
     */
    fetchUserid() {
        return fecthData(this.conf["getUserInfo"])
            .then(res => {
                return res["_id"];
            });
    }

    /**
     *
     * @param id
     * @returns {*}
     */
    fetchPublicPost(id) {
        return fecthData(this.conf["getPublicPostByUserid"].replace("{userid}", id));
    }

    /**
     *
     * @param id
     * @returns {*}
     */
    fetchStudyPost(id) {
        return fecthData(this.conf["getStudyPostByUserid"].replace("{userid}", id));
    }

    /**
     * runTasks
     */
    runTasks() {
        var self = this;

        successLog("api任务开始");

        return Promise
            .all([
                self.fetchUserid()
                    .then(this.fetchUserid.bind(this)),
                self.fetchUserid()
                    .then(this.fetchStudyPost.bind(this))
            ])
            .then(res => {
                successLog("fetchPublicPost:", res[0]);
                successLog("fetchStudyPost:", res[1]);
            })
            .catch(err => {
                warnLog(err);
            })
            .finally(() => {
                successLog("api任务结束");
            });
    }
}
/* sqliteDb.js */
"use strict";

import fs from "fs";

import path from "path";

import Promise from "promise";

import sqlite3 from "sqlite3";

/**
 *
 * @type {*}
 */
global.cache = Object.assign({}, global.cache);

/**
 *
 * @param filepath
 * @returns {*}
 */
function checkDbfile(filepath) {
    return new Promise((resolve, reject) => {
        fs.exists(filepath, isExists => {
            if (isExists) {
                resolve(filepath);
            }
            else {
                fs.writeFile(filepath, "", err => {
                    if (err) {
                        reject(err);
                    }
                    else {
                        resolve(filepath);
                    }
                });
            }
        });
    });
}

/**
 *
 * @param sqliteDb
 * @param statement
 */
async function createTable(sqliteDb, statement) {
    await sqliteDb.run(statement);
}

/**
 *
 * @param config
 * @returns {*}
 */
async function getSqliteDb(config) {
    let sqlite3Cls = config.debug ? sqlite3.verbose() : sqlite3,
        dbpath = path.resolve(config.dbPath),
        sqliteDb = global.cache[dbpath];

    if (!sqliteDb) {

        if (await checkDbfile(dbpath)) {
            sqliteDb = new sqlite3Cls.Database(dbpath);
        }
        else {
            throw new Error("can`t find" + dbpath);
        }
    }

    await createTable(sqliteDb, config.tableStatement);

    return global.cache[dbpath] = sqliteDb;
}

module.exports = {getSqliteDb};
/* analyzer.js*/
"use strict";

import EventEmitter from "events";

import fs from "fs";

import path from "path";

import Promise from "promise";

import {getSqliteDb} from "./sqliteDb";

/**
 *
 * @param dirPath
 * @returns {*}
 */
function readDir(dirPath) {
    return new Promise((resolve, reject) => {
        fs.readdir(dirPath, (err, files) => {
            if (err) {
                reject(err);
            }
            else {
                resolve(files.map(file=> {
                    return path.resolve(dirPath, file);
                }));
            }
        });
    });
}

/**
 *
 * @param filepath
 * @returns {*}
 */
function readFile(filepath) {
    return new Promise((resolve, reject) => {
        fs.exists(filepath, isExists => {
            if (isExists) {
                fs.readFile(filepath, (err, content) => {
                    if (err) {
                        reject(err);
                    }
                    else {
                        resolve(content.toString());
                    }
                });
            }
            else {
                reject(`${filepath} not found\n`);
            }
        });
    });
}

/**
 *
 * @param filePath
 * @returns {*}
 */
function rmFile(filePath) {
    return new Promise((resolve, reject) => {
        fs.unlink(filePath, (err) => {
            if (err) {
                reject(err);
            }
            else {
                resolve(true);
            }
        });
    });
}

/**
 *
 * @param content
 * @returns {*}
 */
function formatSql(content = "") {
    return content.replace(/"/ig, "").split("\n").map(line => {
        return line.split("\t");
    });
}

/**
 *
 * @param db
 * @param record
 * @returns {*}
 */
function insertSingleRecord(db, tableName, record) {
    return new Promise((resolve, reject) => {
        db.run("INSERT INTO " + tableName + "(time, msg, content) VALUES (?, ?, ?);", Object.assign(["", "", ""], record), function(err){
            if (err) {
                reject(err);
            }
            else {
                resolve(this.lastID);
            }
        });
    });
}

/**
 *
 * @param db
 * @param tableName
 * @returns {Function}
 */
function genInsertSqlFunc(db, tableName) {
    return function (records = []) {
        return Promise.all(records.map(record => {
            return insertSingleRecord(db, tableName, record);
        }));
    };
}

/**
 *
 * @param db
 * @param tableName
 * @param filePath
 * @returns {*}
 */
function analysisFile(db, tableName, filePath) {
    return readFile(filePath)
        .then(formatSql)
        .then(genInsertSqlFunc(db, tableName))
        .then(res => {
            rmFile(filePath);
            return res;
        });
}

/**
 *
 * @param db
 * @param tableName
 * @returns {Function}
 */
function genAllFilesAnalysisFunc(db, tableName) {
    return function (files) {
        return Promise.all(files.map((file => {
            return analysisFile(db, tableName, file);
        })));
    };
}

export default class Analyzer extends EventEmitter {

    /**
     *
     * @param conf
     */
    constructor(conf) {
        super();
        this.conf = Object.assign({
            "tableName": "log_record",
            "tableStatement": "CREATE TABLE IF NOT EXISTS log_record  (id INTEGER PRIMARY KEY AUTOINCREMENT, time CHAR(50) NOT NULL, msg CHAR(50) NOT NULL,  content TEXT);",
            "logPath": "./log",
            "debug": false,
            "dbPath": "./data/sqlite.db"
        }, conf);
    }

    /**
     *
     * @returns {*}
     */
    async runTasks() {
        return readDir(path.resolve(this.conf["logPath"]))
            .then(genAllFilesAnalysisFunc(await getSqliteDb(this.conf), this.conf["tableName"]))
            .then(res => {
                console.log(res);
            });
    }
}
/* 入口文件 index.js */
"use strict";

import SpiderPromise from "./spider";

import ApiPromise from "./api";

import Analyzer from "./analyzer";

import config from "../conf/source";

import apiConfig from "../conf/api";

function start(){
    new SpiderPromise(config).runTasks();
    new ApiPromise(apiConfig).runTasks();
    new Analyzer().runTasks();
}

start();
berwin commented 8 years ago

作业一:http://demos.so/result/579035bfd8face55228b1ac2 作业二:http://demos.so/result/57830db7d8face55228b1980

alphatr commented 8 years ago
import fs from 'fs';

/**
 * promisify the callback function
 * @param  {Function} fn         callback function
 * @param  {Object}   receiver   receiver
 * @return {Function}            promise function
 */
const promisify = (fn, receiver) => {
    return (...args) => {
        return new Promise((resolve, reject) => {
            fn.apply(receiver, [...args, (err, res) => {
                return err ? reject(err) : resolve(res);
            }]);
        });
    };
};

const filepath = './promise.txt';

promisify(fs.writeFile, fs)(filepath, 'first line').then(() => {
    console.log('writeFile success');
}).then(() => {
    return promisify(fs.appendFile, fs)(filepath, '\nsecond line').then(() => {
        console.log('appendFile success');
    });
}).then(() => {
    return promisify(fs.readFile, fs)(filepath, 'UTF-8').then(content => {
        console.log('readFile success');
        console.log(content);
    });
}).catch(error => {
    console.error(error);
});
jedmeng commented 8 years ago
/* wrap.js */
'use strict';

function wrap(fn, context) {
    let args = [].slice.call(arguments, 2);
    return new Promise ((resolve, reject) => {
        args.push(function(error) {
            error ? reject(error) : resolve.apply(null, [].slice.call(arguments, 1));
        });
        fn.apply(context, args);
    });
}

module.exports = wrap;
/* 第一题 */
'use strict';

const fs = require('fs');
const os = require('os');
const path = require('path');
const wrap = require('./wrap');

const tmpFile = path.join(os.tmpdir(), 'promiseTmpFile');

wrap(fs.writeFile, fs, tmpFile, 'Hello ')
    .then(() => wrap(fs.appendFile, fs, tmpFile, 'world!'))
    .then(() => wrap(fs.readFile, fs, tmpFile))
    .then(content => console.log(`File content: ${content}`))
    .catch(error => console.log('io error!', error));
/* 第二题 */
'use strict';

const wrap = require('./wrap');
const request = require('request');

const getUserInfoAPI = 'http://demos.so/result/homework.promise.userInfo';
const getuserPublishAPI = 'http://demos.so/result/userid';
const getuserLearnAPI = 'http://demos.so/result/student';
const httpTimeout = 30;

const httpGet = function(url) {
    let timer;
    return Promise.race([
        new Promise((_, reject) =>
            timer = setTimeout(() => reject('request time out'), httpTimeout * 1000)
        ),
        wrap(request, null, url).then(response => {
            clearTimeout(timer);
            return JSON.parse(response.body);
        })
    ]);
};

httpGet(getUserInfoAPI)
    .then(userInfo => Promise.all([
        httpGet(`${getuserPublishAPI}=${userInfo._id}`),
        httpGet(`${getuserLearnAPI}=${userInfo._id}`)
    ]))
    .then(data => {
        console.log('user published:', data[0].map(item => item.title).join('、'));
        console.log('user learned:', data[1].map(item => item.title).join('、'));
    })
    .catch(error => console.log('network error:', error));
bingomvm commented 8 years ago
var Promise = require("promise");
var fs = require("fs");
var request = require("request");
const filename = "test.txt";
const userInfoUrl = "http://demos.so/result/homework.promise.userInfo";
const learnUrl = "http://demos.so/result/student=";
const postUrl = "http://demos.so/result/userid=";
/*作业一*/
function controlFile(filename,type,data) {
    return new Promise((resolve,reject) => {
        var readFile = (type == "readFile");
        var controlType = (readFile ? "utf8" : data);
        fs[type](filename,controlType,(err,data) => {
            if (err) reject(err);
            readFile && console.log(data);
            resolve(data);
        })

    })
}
controlFile(filename,"writeFile","hello world")
.then(controlFile(filename,"appendFile"," again world"))
.then(controlFile(filename,"readFile"));

/*作业二*/
function promiseAjax(url) {
    return new Promise(function(resolve,reject) {
        request(url, function (error, response, body) {
            if (!error && response.statusCode == 200) {
                resolve(JSON.parse(body)); 
            } else {
                reject(error);
            }
        })
    })
}
function timeout(time) {
    return new Promise(function(resolve,reject) {
        setTimeout(function() {
            reject("timeout");
        },time);
    });
}
promiseAjax(userInfoUrl)
.then(function(userInfo) {

    var id = userInfo._id;
    var getSuccess =  Promise.all([promiseAjax(postUrl + id),promiseAjax(learnUrl + id)])
    return Promise.race([getSuccess,timeout(1000)]);
})
.then(function(data) {
    console.log(data);
},function(){
    console.log("1111");
})
.catch(function(err) {
    console.log(err);
})
liuyan12 commented 8 years ago
/********************** 作业一 *************************/ 
var fs = require('fs');
function writeFile(){
    return new Promise(function(resolve,reject){
        var data = "写入数据到file.txt文件中";
        fs.writeFile('file.txt',data,'utf-8',function(err){
            if(err){
                reject(new Error(err));
                return;
            }else{
                resolve();
            }           
        });
    })
}
function appendFile(){
    return new Promise(function(resolve,reject){
        var data = "\n\n追加数据到file.txt文件中";
        fs.appendFile('file.txt',data,'utf-8',function(err){
            if(err){
                reject(new Error(err));
                return;
            }else{
                resolve();
            }
        })
    });
}
function readFile(){
    return new Promise(function(resolve,reject){
        fs.readFile('file.txt','utf-8',function(err,data){
            if(err){
                reject(new Error(err));
            }else{
                console.log(data);
            }
        })
    });
}
var promise = Promise.resolve();
promise.then(writeFile)
            .then(appendFile)
            .then(readFile)
            .catch(function(error){
                console.log("抛出异常:"+ error);
            });

/********************** 作业二 *************************/ 
var request = require('request');

function requestFun(URL){
    return new Promise(function (resolve, reject){
        request(URL,function(error, response, data){
            if (!error && response.statusCode == 200) {
                resolve(data);
            }else{
                reject(error);
            }
        })
    })
};

var reqInfo = {
    getUserId: function () {
        return requestFun('http://demos.so/result/homework.promise.userInfo').then(function(data){
            return JSON.parse(data)['_id'];
        })
    },
    getUserStudy : function(){
        return this.getUserId().then(function(id){
            return requestFun('http://demos.so/result/student='+ id).then(JSON.parse);
        });
    },
    getUserIssue : function(){
        return this.getUserId().then(function(id){
            return requestFun('http://demos.so/result/userid='+ id).then(JSON.parse);
        });
    },
    promiseAll : function(){
        return Promise.all([this.getUserStudy(),this.getUserIssue()])
    },
    promiseRace : function(){
        return Promise.race([this.getUserStudy(),this.getUserIssue(),this.reqTimeout()]);       
    },
    reqTimeout : function(){
        return new Promise(function(resolve,reject){
            setTimeout(function(){
                resolve("您的请求超时了~~~~~~~~~~~~~~~~");
            },200);
        })
    }
}

/**
    promise.all 
    用户发布的帖子和用户学习帖子同时并行请求 
*/
reqInfo.promiseAll().then(function(value){
    console.log("\n\n\n\npromise.all:\n");
    console.log("用户学习过的帖子:\n");
    console.log(value[0]);
    console.log("\n用户发布的帖子:\n");
    console.log(value[1]);
},function(error){
    console.log(error);
}).catch(function(error){
    conosle.log(error);
})

/**
    promise.race 
    用户发布的帖子和用户学习帖子同时并行请求 
*/
reqInfo.promiseRace().then(function(value){
    console.log("\n\n\n\npromise.race:\n");
    console.log("请求快的先显示:");
    console.log(value);
},function(error){
    console.log(error);
}).catch(function(error){
    conosle.log(error);
})
wuyan198410 commented 8 years ago
/*作业1*/
var fs = require('fs'),
    promuse = Promise.resolve();
promuse.then(function(){
    fs.writeFile('promise.txt','hello promise',(err) => {
        if(err){
            reject(new Error(err));
        }
    });
}).then(function(){
    fs.appendFile('promise.txt',' data to appendFile',(err) => {
        if(err){
            reject(new Error(err));
        }
    });
}).then(function(){
    fs.readFile('promise.txt','utf8',(err , data) => {
        if(err){
            reject(new Error(err));
        }
        console.log(data);
    })
}).catch(function(error){
    console.log(error);
});

/*作业2*/

var http = require('http'),
    infoApi = 'http://demos.so/result/homework.promise.userInfo',
    pubApi = 'http://demos.so/result/userid=',
    learnApi = 'http://demos.so/result/student=';

function delayPromise(ms) {
  return new Promise(function (resolve) {
    setTimeout(resolve, ms);
  });
}

function timeoutPromise(promise, ms) {
  var timeout = delayPromise(ms).then(function () {
    throw new Error('超时' + ms + ' ms');
  });
  return Promise.race([promise, timeout]);
}

function getData(url) {
    return new Promise(function(resolve,reject) {
      http.request(url, (res) => {
        var data;
        res.setEncoding('utf8');
        res.on('data', (chunk) => {
          data = JSON.parse(chunk);
        });
        res.on('end', () => {
          resolve(data);
        })
      }).on('error', function(error) {
          reject(error)
      }).end();
    })
}

timeoutPromise(getData(infoApi),1000).then(function(data){
  var id = data._id;
  return Promise.all([timeoutPromise(getData(pubApi + id),1000),timeoutPromise(getData(learnApi + id),1000)]);
}).then(function(data){
  console.log('发布的帖子')
  console.log(data[0])
  console.log('学习的帖子')
  console.log(data[1])
}).catch(function(error){
  console.log(error)
});
BullseyeBao commented 8 years ago

//fs 'use strict'; let fs = require('fs'), fileName = "file.txt", result = "";

new Promise((resolve, reject) => { let str = "随便写点什么"; fs.writeFile(fileName, str, resolve); }).then((err) => { return new Promise((resolve, reject) => { if(err){ reject(err); } var str2 = "随便追加点什么"; fs.appendFile(fileName, str2, resolve); }); }).then((err) => { return new Promise((resolve, reject) => { if(err){ reject(err); } fs.readFile(fileName, (err, data) => {resolve(data)}); }); }).then((data) => { return new Promise((resolve, reject) => { console.log(data.toString()); });

}).catch((err) => { console.log("err: " + err); })

//request let request = require('request'), getReqPromise = (url, timeout) => { return new Promise((resolve, reject) => { if(timeout){ setTimeout(() => { reject("timeout"); }, timeout); } request(url, function(err, response, body){ if(err){ reject(err); } else if(response.statusCode == 200){ let data = JSON.parse(body); resolve(data); } }); }); }, url1 = "http://demos.so/result/homework.promise.userInfo", url2 = "http://demos.so/result/userid=", url3 = "http://demos.so/result/student=";

getReqPromise(url1).then((data) => { let id = data['_id']; Promise.all([getReqPromise(url2 + id), getReqPromise(url3 + id)]).then((datas) =>{ console.log("发布的帖子:"); console.log(data[0]); console.log("学习的帖子:"); console.log(data[1]); }).catch((err) => { console.log("err: " + err); }); }).catch((err) => { console.log("err: " + err); });

crossai-2033 commented 8 years ago
module.exports = promisify

function promisify(fn) {
  return wrapper(fn)
}

function createCallback(resolve, reject) {
  return function(err, value) {
    if (err) return reject(err)
    var length = arguments.length
    if (length <= 2) return resolve(value)
    var values = new Array(length - 1)
    for (var i = 1; i < length; ++i) values[i - 1] = arguments[i]
    resolve(values)
  }
}

function wrapper(fn) {
  return (function() {
    var self = this
    var len = arguments.length
    var args = new Array(len + 1)
    for (var i = 0; i < len; ++i) args[i] = arguments[i]
    var lastIndex = i
    return new Promise(function (resolve, reject) {
      args[lastIndex] = createCallback(resolve, reject)
      fn.apply(self, args);
    })
  })
}

function PromisifyAll(source, destination, methods) {
  return promisifyAll(source, destination, methods, promisify)
}

function promisifyAll(source, destination, methods, promisify) {
  if (!destination) {
    destination = {}
    methods = Object.keys(source)
  }

  if (Array.isArray(destination)) {
    methods = destination
    destination = {}
  }

  if (!methods) {
    methods = Object.keys(source)
  }

  if (typeof source === 'function') destination = promisify(source)

  methods.forEach(function (name) {
    if (typeof source[name] === 'function') destination[name] = promisify(source[name])
  })

  Object.keys(source).forEach(function (name) {
    if (destination[name]) return
    destination[name] = source[name]
  })

  return destination
}

/**
 * 第一题
 */
var fs = PromisifyAll(require('fs'), {}, [
  'readFile',
  'writeFile',
  'appendFile',
])

var readme = __dirname + '/README'
fs.writeFile(readme, 'Hello 小灶会\r\n')
  .then(fs.appendFile(readme, '欢迎参加'))
  .then(() => {
    fs.readFile(readme).then(content => {
      console.log(content.toString())
    })
  })
zhaoyan1986 commented 8 years ago
/* 第一题 */
var fs = require('fs');
var fileName = '1.txt';

var firstWrite = function () {
    return new Promise(function (resolve, reject) {
        var str = +new Date() + '\n';
        fs.writeFile(fileName, str, function(err){
            if(err) reject(err);
            resolve();
        })
    })
}

var appendWrite = function () {
    return new Promise(function (resolve, reject) {
        var str = +new Date() + '\n';
        fs.appendFile(fileName, str, function(err){
            if(err) reject(err);
            resolve();
        })
    })
}

var log = function () {
    return new Promise(function (resolve, reject) {
        fs.readFile(fileName, function(err, data){
            if(err) reject(err);
            console.log(data.toString());
        })
    })
}

firstWrite().then(appendWrite).then(log).catch(function (err) {
    console.log(err);
});

/* 第二题 */
var request = require('request');

var userApi = 'http://demos.so/result/homework.promise.userInfo',
    demosApi = 'http://demos.so/result/';
var demosTypes = ['userid', 'student'];

var TIMEOUT = 1000;

var delayPromise = function (ms) {
    return new Promise(function (resolve) {
        setTimeout(resolve, ms);
    })
};

var timeoutPromise = function(promise, ms) {
    var timeout = delayPromise(ms).then(function() {
        throw new Error('Operation timed out after' + ms + ' ms');
    })

    return Promise.race([promise, timeout]);
}

var getUserInfo = function () {
    var task =  new Promise(function (resolve, reject) {
        request.get({url: userApi, json: true}, function (error, response, body) {
            if(error) reject(err);
            if(response.statusCode != 200) reject(response.statusCode);
            resolve(body);
        })
    })

    return timeoutPromise(task, TIMEOUT);
}

var getDemos = function (userInfo) {
    return Promise.all(
        demosTypes.map(function (type) {
            var url = demosApi + type + '=' + userInfo._id;
            var task = new Promise(function (resolve, reject) {
                request.get({url, url, json: true}, function (error, response, body) {
                    if(error) reject(err);
                    if(response.statusCode != 200) reject(response.statusCode);
                    resolve(body);
                })
            })
            return timeoutPromise(task, TIMEOUT);
        })
    )
}

getUserInfo().then(getDemos).then(function (data) {
    console.log(data);
}).catch(function (err) {
    console.log(err);
});
fei207 commented 8 years ago
/* 1 */
var fs = require('fs');

new Promise((resolve, reject) => {
    fs.writeFile('./1.txt', 'writeFile done', (err) => {
        if(err) reject(err);
        console.log('write success');
        resolve();
    })
}).then(() => {
    return new Promise((resolve, reject) => {
        fs.appendFile('./1.txt', '\nappendFiel done', (err) => {
            if(err) reject(err);
            console.log('append success');
            resolve();
        })
    })

}).then(() => {
    return new Promise((resolve, reject) => {
        fs.readFile('./1.txt', 'utf-8', (err, data) => {
            if(err) reject(err);
            console.log(data);
            resolve();
        })
    })
}).catch((err) => {
    console.log('err', err);
})
/* 2 */
var request = require('request');

var userApi = 'http://demos.so/result/homework.promise.userInfo',
    pubApi = 'http://demos.so/result/userid=',
    studyApi = 'http://demos.so/result/student=',
    timeout = 2;

var timeoutFun = function (promise, timeout) {
    var t = new Promise(function (resolve, reject) {
        setTimeout(resolve, timeout)
    }).then(function () {
        throw new Error ('operation timed out');
    })

    return Promise.race([promise, t]);
}

new Promise(function (resolve, reject) {
    request.get({url: userApi, json: true}, function (err, response, body) {
        if (err) reject(err);
        resolve(body)
    })
}).then(function (userInfo) {
    return Promise.all([
        timeoutFun(new Promise(function (resolve, reject) {
            console.log('pubApi', pubApi + userInfo._id);
            request.get({url: pubApi + userInfo._id, json: true}, function (error, reponse, body) {
                if (error) reject(error);
                resolve(body)
            })
        }), timeout),
        timeoutFun(new Promise(function (resolve, reject) {
            console.log('studyApi', studyApi + userInfo._id);
            request.get({url: studyApi + userInfo._id, json: true}, function (error, reponse, body) {
                if (error) reject(error);
                resolve(body)
            })
        }), timeout)
    ])
}).then(function (datas) {
    console.log(datas);
}).catch(function (err) {
    console.log('err', err);
})
tongshouyu1019 commented 8 years ago
/*学习了大家的代码,新改了一份~~*/
/*第一题*/
var fs = require('fs');

function wrapper(fn,context) {
    var args = Array.prototype.slice.call(arguments,2);
    return new Promise((resolve,reject) => {
        args.push((err,data) => {
            err ? reject(err) : resolve(data);
        });
        fn.apply(context,args);
    });
}

wrapper(fs.writeFile,fs,'message.txt','word')
    .then(() => wrapper(fs.appendFile,fs,'message.txt','word'))
    .then(() => wrapper(fs.readFile,fs,'message.txt','word'))
    .then(data => console.log(data))
    .catch(err => console.log(err));

/*第二题*/
var http = require('http');
var url = require('url');

function delayPromise(ms) {
    return new Promise((resolve,reject) => {
        setTimeout(reject, ms);
    });
}

function get(url,ms) {  
    return new Promise.race([
        delayPromise(ms),
        wrapper(request,null,url).then(data => {
            return JSON.parse(data);
        })
    ]);

}

get('http://demos.so/result/homework.promise.userInfo')
    .then( data => {
        Promise.all([get('http://demos.so/result/userid=' + args['_id']), get('http://demos.so/result/student=' + args['_id'])])
    }
    .then( data => console.log(data))
    .catch( err => console.log(args));
qijunxin commented 8 years ago

/*
 *作业一:
 */
var fs = require('fs');
Promise.resolve().then(function(){
    return new Promise(function(resolve,reject){
            fs.writeFile('test.txt', 'Qi Junxin gets to learn Promise!', function(err){
        err ? reject(err) : resolve();
    });
})
}).then(function(){
    return new Promise(function(resolve,reject){
            fs.appendFile('test.txt', 'This is the second part.', function(err){
        err ? reject(err) : resolve();
    });
})
}).then(function(){
    return new Promise(function(resolve,reject){
            fs.readFile('test.txt','utf8',function(err,data){
                err ? reject(err) : console.log(data);
    })
})
}).catch(function(err){
    console.log(err);
});

/*
 *作业二:
*/

var request = require('request'),
    userInfo = 'http://demos.so/result/homework.promise.userInfo',
    publicUrl = 'http://demos.so/result/userid=',
    studyUrl = 'http://demos.so/result/student=';
var delay = 1000; //ms

var timeoutCtrl = function(){
    return new Promise(function(resolve,reject){
    setTimeout(function(){
              reject('Timeout'+delay+'ms')}, 
        delay);
    })
};

var getWithPromise = function(url){
    var task = new Promise(function(resolve,reject){
        request.get({url: url, json: true}, function (error, response, body) {
                if(error) reject(err);
                if(response.statusCode != 200) reject(response.statusCode);
                resolve(body);
         });
    });
    return Promise.race([task,timeoutCtrl()]);
};

var getPost = function(user){
    return Promise.all([getWithPromise(publicUrl+user['_id']),getWithPromise(studyUrl+user['_id'])]);
};

getWithPromise(userInfo).then(getPost).then(function (data) {
    console.log(data);
}).catch(function (err) {
    console.log(err);
});
onistbin commented 8 years ago

var fs = require('fs');

function writeFile(filename, data) {

    return new Promise (function(resolve, reject) {

        fs.writeFile(filename, data, function(err){

            if(err)
                reject(err);
            else 
                resolve();
        });

        // setTimeout(function () {
        //     resolve(11);
        // }, 2000)
    }); 
} 
function appendFile(filename, data) {

    return new Promise (function(resolve, reject) {

        fs.appendFile(filename, data, function(err){

            if(err)
                reject(err);
            else 
                resolve();
        });
    }); 
} 
function readFile(filename) {

    return new Promise (function(resolve, reject) {

        fs.readFile(filename, 'utf8', function(err, data){
            if(err) 
                reject(err);
            else 
                console.log(data);
        });
    }); 
} 

Promise.resolve().then(function(){

    return writeFile('./test.txt', 'Hello');
}).then(function(){
    console.log(22);

    return appendFile('./test.txt', 'World');
}).then(function(){
    console.log(33)

    return readFile('./test.txt');
}).catch(function(err){

    console.log(err);
});

----------------------------------------------------------------------------------

var request = require('request');

var url = "http://demos.so/result/homework.promise.userInfo",
    useUrl = "http://demos.so/result/userid=",
    studyUrl = "http://demos.so/result/student=";

function requestPromise(url) {

    return new Promise(function (resolve, reject) {

        request(url, function (error, response, data) {
            if (!error && response.statusCode == 200) {

                var jsonData = JSON.parse(data);

                resolve(jsonData);
                //console.log(jsonData);
            }
        });
    });
}

function getUse(data) {
    return requestPromise(useUrl + data._id);
}

function getStudy(data) {
    return requestPromise(studyUrl + data._id);
}

requestPromise(url).then(function(data) {
    return Promise.all([getUse(data), getStudy(data)]);
}).then(function(data) {
    console.log(data[0], data[1]);
});
pengyfpengyf commented 8 years ago
/**
作业1:
**/
var fs = require('fs');
opFile = {
    fileName : 'a.txt',
    str1 : 'this is my wirte - string!',
    str2 : 'append to this !',
    main : function(){
        this.writeFile(this.fileName,this.str1).then(
            this.appendFile(this.fileName,this.str2)
        ).then(
            this.readFile(this.fileName)
        ).catch(function (err){ 
            console.log(err)
        })
    },
    //写文件
    writeFile : function (filename,string){
        return new Promise(function (resolve, reject){
            fs.writeFile(filename, string, 'utf8',function (err){
                if (err){ 
                    reject(err)
                }else { 
                    resolve();
                }
            })
        });
    },
    //文件内容追加
    appendFile : function (filename,string) {
        return new Promise(function (resolve, reject){          
            fs.appendFile(filename, string, 'utf8',function (err){
                if (err){ 
                    reject(err)
                }else { 
                    resolve()
                }
            })
        })
    },
    //文件读取
    readFile : function (filename){
        fs.readFile(filename, 'utf8', function (err, res){
            if (err){ 
                console.log(err)
            }else { 
                console.log('读文件'+filename+'结果为:', res);
            }
        });
    }
}
opFile.main();
/**********************/
 /**
作业2:
**/
var request = require('request');
getInfo = {
    // 获取用户ID等信息 
    getId : function() {
        return new Promise(function (resolve, reject){
            request('http://demos.so/result/homework.promise.userInfo', function (error, response, data) {
                if (!error && response.statusCode == 200){
                    resolve(data)
                }else{
                    reject(err)
                }
            });
        });
    },
    //用户发布过的帖子
    getPub : function(id){
        return new Promise(function (resolve, reject){
            request('http://demos.so/result/userid='+id, function (error, response, data) {
                if (!error && response.statusCode == 200){
                    resolve(data)
                }else{
                    reject(err)
                }
            });
        });
    },
    //用户学习过的帖子
    getStu : function(id){
        return new Promise(function (resolve, reject){
            request('http://demos.so/result/student='+id, function (error, response, data) {
                if (!error && response.statusCode == 200){
                    resolve(data)
                }else{
                    reject(err)
                }
            });
        });
    },
    //并发请求
    all : function(id){
        var self = this;
        Promise.all([self.getPub(id),self.getStu(id)]).then(function (results){
            console.log(results);
        }).catch(function(error){
            console.log('catch',error);
        });
    },
    main : function(){
        var self = this;
        self.getId().then(function(data){
            //这里返回的data为字符串类型
            var userinfo = JSON.parse(data);
            var id = userinfo._id;
            self.all(id);
        })
    }
}
getInfo.main();