blog icon indicating copy to clipboard operation
blog copied to clipboard

【面经】字节跳动 三面8:顺序发送 4 个请求 a,b,c,d,要求按照顺序输出

Open liam61 opened this issue 5 years ago • 14 comments

顺序发送 4 个请求 a,b,c,d,要求按照顺序输出

利用数组缓存,再按照标志依次输出

function getData(urls) {
  // 感谢 @jinxin0112 的指正
  return new Promise((resolve, reject) => {
    const res = [], len = urls.length;
    urls.forEach((url, i) => {
      fetch('http://localhost:8080' + url).then(data => data.json())
        .then(data => {
          res[i] = { data, printed: false }; // 将数据放入缓存数组
          let flag = true;
          for (let j = 0; j < len && flag; j += 1) {
            if (res[j]) { // 如果标志为 j 的有返回值,则继续
              if (!res[j].printed) {
                console.log(res[j].data);
                res[j].printed = true;
                j === len - 1 && resolve(res.map(o => o.data))
              }
            } else { // 无返回值,则跳出
              flag = false;
            }
          }
        }, reject);
    });
  })
}

const listPromise = getData(['/data.json', '/data2.json', '/data3.json', '/data4.json']);
listPromise.then(res => console.log(res));

// server.js 测试:模拟各个请求延迟返回
const express = require('express');
const cors = require('cors');
const app = express();

const getTime = () => Math.floor(Math.random() * 4 * 1000);

app.use(cors({ origin: '*' }));

app.use('/data.json', (req, res) => {
  setTimeout(() => res.end(JSON.stringify({ a: 1 })), getTime());
});

app.use('/data2.json', (req, res) => {
  setTimeout(() => res.end(JSON.stringify({ b: 2 })), getTime());
});

app.use('/data3.json', (req, res) => {
  setTimeout(() => res.end(JSON.stringify({ c: 3 })), getTime());
});

app.use('/data4.json', (req, res) => {
  setTimeout(() => res.end(JSON.stringify({ d: 4 })), getTime());
});

app.listen(8080, () => console.log('the app is running at http://localhost:8080'));

liam61 avatar Mar 21 '19 03:03 liam61

这题不能用 promise 吗

jinxin0112 avatar Nov 22 '19 12:11 jinxin0112

这题不能用 promise 吗

不清楚,欢迎指教哦

liam61 avatar Nov 22 '19 15:11 liam61

Promise.all 包4个fetch ?

jinxin0112 avatar Nov 25 '19 03:11 jinxin0112

Promise.all 包4个fetch ?

读题哦,是顺序发送,promise.all 是并发。然后是一个请求如果拿到结果,并且顺序为1,就马上输出,如果顺序为2,等顺序为1的请求输出后再输出,promise.all 是等全部请求都成功了才返回结果

liam61 avatar Nov 25 '19 08:11 liam61

function getData(urls) {
	return new Promise((resolve, reject) => {
		const res = Array.from({ length: urls.length });

		urls.forEach((url, i) =>
			fetch(url).then(data => {
				res[i] = [i, data];
				check();
			}, reject)
		);

		function check(i) {
			const realRes = res.filter(Boolean);
			for (let k = 0; k < realRes.length; k++) {
				if (realRes.map(([j]) => j)[k] !== k) return;
			}
			resolve(realRes.map(([_, data]) => data));
		}
	});
}

jinxin0112 avatar Nov 26 '19 07:11 jinxin0112

@lawler61 你这个直接return res怕是不得行哦

jinxin0112 avatar Nov 26 '19 07:11 jinxin0112

function getData(urls) {
	return new Promise((resolve, reject) => {
		const res = Array.from({ length: urls.length });

		urls.forEach((url, i) =>
			fetch(url).then(data => {
				res[i] = [i, data];
				check();
			}, reject)
		);

		function check(i) {
			const realRes = res.filter(Boolean);
			for (let k = 0; k < realRes.length; k++) {
				if (realRes.map(([j]) => j)[k] !== k) return;
			}
			resolve(realRes.map(([_, data]) => data));
		}
	});
}

你这个 realRes 没把数组锁住,先返回的数据会白 resolve 掉,再者 check 算法遍历数组太多次,数据多了会造成性能问题哦

607F7986-F230-48A6-B21C-A628793801EA

liam61 avatar Nov 26 '19 14:11 liam61

@lawler61 你这个直接return res怕是不得行哦

你说的这个是对的哈,整体包个 promise 即可

liam61 avatar Nov 26 '19 14:11 liam61

受教了。。😄

jinxin0112 avatar Nov 27 '19 01:11 jinxin0112

async await不行吗

vnues avatar Sep 21 '20 04:09 vnues

async await不行吗

可以给个demo,不过请理解题目,是顺序(并行)发送,不是一个请求发送且响应后再发下一个,那这就不是面试题了

liam61 avatar Sep 21 '20 06:09 liam61

试了一下用Promise.all好像确实可以

let url = 'http://localhost:8080'

    async function p1(param) {
        return await fetch(url + param).then(res => res.json()).then(res => res)
    }
    async function p2(param) {
        return await fetch(url + param).then(res => res.json()).then(res => res)
    }

    async function p3(param) {
        return await fetch(url + param).then(res => res.json()).then(res => res)
    }

    async function p4(param) {
        return await fetch(url + param).then(res => res.json()).then(res => res)
    }

    Promise.all([p1('/data.json'), p2('/data2.json'), p3('/data3.json'), p3('/data4.json')]).then(res => {
        console.log(res, '结果') //[1,2,3,4]
    })

const express = require('express'); const cors = require('cors'); const app = express();

const getTime = () => Math.floor(Math.random() * 4 * 1000);

app.use(cors({ origin: '*' }));

app.use('/data.json', (req, res) => { setTimeout(() => res.end(JSON.stringify({ a: 1 })), 5000); });

app.use('/data2.json', (req, res) => { setTimeout(() => res.end(JSON.stringify({ b: 2 })), 1000); });

app.use('/data3.json', (req, res) => { setTimeout(() => res.end(JSON.stringify({ c: 3 })), 600); });

app.use('/data4.json', (req, res) => { setTimeout(() => res.end(JSON.stringify({ d: 4 })), 100); });

app.listen(8080, () => console.log('the app is running at http://localhost:8080'));

gaoxinxiao avatar Sep 13 '21 06:09 gaoxinxiao

@gaoxinxiao 是a一回来就输入哦,如果是 b 先回来,要等a输出了,才接着输出,而不是Promise.all 所有接口完成后才看到接口。即使是Promise.all 原理能不能手写出来呢~

liam61 avatar Sep 14 '21 02:09 liam61

@gaoxinxiao是一回来就输入哦,如果是b先回来,要等一个输出,才输出,而不是承诺。所有接口所有完成后看到接口。即使是承诺。所有原理能不能手写出来呢~

我试了一下你写的那个例子也是一起回来的 就算先请求a然后a慢返回b先返回 也是一起展示的

gaoxinxiao avatar Sep 23 '21 11:09 gaoxinxiao