promise 如何处理后一个then需要前一个then的数据?
发布于 9 年前 作者 XGHeaven 21572 次浏览 最后一次编辑是 8 年前 来自 问答

比如现在有一个情景,就是传入一个token,根据这个token请求一次网络,然后获取用户ID,讲获取的用户ID访问数据库,获取用户信息,讲用户信息和ID一起写入到一个文本中去,在这样的一个流程中,传统的是需要这样的。

request(token)
	.then(function(id) {
		mongodb
			.find(id).toArray()
			.then(function(info){
				fs.writeFile(filename, info+id)
					.then(function(){console.log('success');}
			})
	})

但是如果按照这样的话,如果需求要多的话,似乎又掉入了回调地狱,那么有什么问题可以解决这个问题呢?就是后面的异步操作都需要前面异步操作的值,或者自定义的值?

7 回复

用链式调用写法,第一个 then 的返回值是第二个 then 的参数。

刚才在手机上回复的,没法敲代码。简单来说,你的例子可以改成这样:

let tokenId, filename = 'xxx'

request(token).then(id => {
  tokenId = id
  return mongodb.find(id).toArray()
}).then(info => {
  return fs.writeFile(filename, `${info}${tokenId}`)
}).then(() => {
  console.log('success')
})

每个 then 里面需要共享的变量只能放到 then 外面去定义了。

模拟查询方法

var request = function (token) {
    return new Promise((resolve, reject)=> {
        setTimeout(
            ()=> {
                token ? resolve(2) : reject('token error');
            },
            1000
        )
    });
};

var find = function (id) {
    return new Promise((resolve, reject)=> {
        setTimeout(
            ()=> {
                id ? resolve(id + '-info') : reject('id error');
            },
            1000
        )
    });
};

Promise

一般来说promise的链式调用时这样的

request('token')
    .then(function (id) {
        return find(id);
    })
    .then(function (info) {
        console.log( info);
    });

像楼主所说的情况需要记录id,所以改成如下

var data = {};
request('token')
    .then(function (id) {
        data.id = id;
        return find(id);
    })
    .then(function (info) {
        console.log(data.id, info);
    });

很不优雅。Promise的缺点就是链过长以后分不清业务到底干了写啥,满屏幕的then。

Generator

ES有个新特性叫Generator,结合TJ大神的 co,可以将代码写成如下

co(function *() {
    var id = yield request('token');
    var info = yield find(id);

    console.log(id, info);
});

看起来舒服多了,但是毕竟还是用到了第三方的库

async

ES7的提案,代码写法如下

(async function () {
    var id = await request('token');
    var info = await find(id);

    console.log(id, info);
})();

新特性需要babel转码。 以上就是我所了解的。

@darkbaby123 我主要是不想共享变量到外面去😷 自豪地采用 CNodeJS ionic

@yuyang041060120 那我试一下co库 自豪地采用 CNodeJS ionic

var Promise2 = require('bluebird');
request(token).then(id => Promise2.all([ id, mongodb.find(id).toArray() ]).spread((id, info) => here);

@klesh 方法不错,话说reduce可以么?

来自炫酷的 CNodeMD

@XGHeaven 我想不太适用你的场景吧,你可以试一下。。。

回到顶部